Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 泛型、可空、类型推断和函数签名冲突_C#_Generics_Asynchronous_Nullable_Method Signature - Fatal编程技术网

C# 泛型、可空、类型推断和函数签名冲突

C# 泛型、可空、类型推断和函数签名冲突,c#,generics,asynchronous,nullable,method-signature,C#,Generics,Asynchronous,Nullable,Method Signature,我有以下代码: public async static Task<T?> RequestValue1<T>(Command requestCommand) where T : struct { // Whatever } public async static Task<T> RequestValue2<T>(Command requestCommand)

我有以下代码:

public async static Task<T?> RequestValue1<T>(Command requestCommand)
                    where T : struct 
{
    // Whatever
}

public async static Task<T> RequestValue2<T>(Command requestCommand)
                    where T : class 
{
    // Whatever
}
公共异步静态任务RequestValue1(命令requestCommand) 其中T:struct { //随便 } 公共异步静态任务RequestValue2(命令requestCommand) T:在哪里上课 { //随便 } 我希望我的两个方法具有相同的名称这可能吗?

我的问题:

  • 我必须编写两种不同的方法,因为返回类型是
    null
    if
    T
    是值类型,而
    T
    if
    T
    的实例是引用类型
  • async
    不允许ref/out,因此如果没有类型为
    t
    的方法参数,
    t
    将不会被推断,并且我的两个方法不能具有相同的名称(签名冲突,因为如果
    t
    未被推断,则通用约束不适用于签名冲突解决)

目前该代码可以正常工作,但我不喜欢在“RequestValue1”和“RequestValue2”之间调用这种奇怪的函数。

您可以创建自己的
选项
类型,并使用它来指示是否返回值:

public async static Task<Option<T>> RequestValue<T>(Command requestCommand) {
  ...
}

您可以删除该约束,并使调用方将
null
类型传递给您的方法(即调用
RequestValue(cmd)
而不是
RequestValue(cmd)
)。您可以确保在运行时为空,如下所示:

public async static Task<T> RequestValue<T>(object arg) {
    var t = typeof (T);
    if (!t.IsClass && (!t.IsGenericType || t.GetGenericTypeDefinition() != typeof(Nullable<>))) {
        throw new ArgumentException("T");
    }
    // Whatever
}
公共异步静态任务请求值(对象arg){
var t=类型(t);
如果(!t.IsClass&&(!t.IsGenericType | | t.GetGenericTypeDefinition()!=typeof(可为null))){
抛出新的ArgumentException(“T”);
}
//随便
}

可以有如下方法签名:

    static void test1<T>(Nullable<T> param) where T:struct;
    static void test1<T>(T param) where T:class;
我并不特别喜欢这种模式,因为
Result
不可能是协变的或参与类型推断。另一种选择是:

static Task<T> RequestValue1<T>(Command requestCommand, out bool Success);
static Task RequestValue1(Command requestCommand,out bool Success);
这种形式对协方差没有问题。另一种形式是:

static Task<T> RequestValue1<T>(Command requestCommand, out ResultStatus Status);
静态任务请求值1(命令请求命令,输出结果状态);
其中ResultStatus将是一个类型,具有一个
successed
方法,在成功的情况下返回
True
,但可以有其他成员解释失败时的错误。如果它是一个不可变的抽象类型,定义了一个单例
Success
实例,以便在工作时使用,那么将来可以扩展它,在工作不正常时提供任意级别的细节,而不会在工作时造成任何GC压力


不幸的是,即使是
out
参数类型不依赖于
t
的形式也不能在某些上下文中使用。考虑到这一点,我们可以定义一个结构类型
CommandResult
,它将
T
与成功指示符相结合,在概念上类似于
Nullable
,但对其参数类型没有恼人的
struct
约束。成功指示器可以是一个
bool
,也可以是一个如上所述的状态指示器。

@Ryan否。我尝试了这个方法,但是如果我没有设置通用约束,则
null
不会编译,其中
t
:struct on
t
:“出于方法重载的目的,方法的返回类型不是方法签名的一部分。“-但是给另一个输入参数来区分如何?如果不是相同的名称,您可以给它们更好的名称,例如
RequestClass
RequestStruct
,而不是
1
2
。您能否不总是调用
RequestValue2
变量,而是使用类型参数
int?
”,
double?
等。而不是
int
double
等。@Servy,是的,如果我没有收到这个问题的答案,我该怎么办。这个问题是想知道我是否遗漏了什么:)如果你总是传入一个可为null的类型,那么你可以用
default(t)
代替
null
。如果有人想使用不可为空的类型……它不应该是世界末日。@Servy,它实际上是我的“世界末日”,因为这种方法是不确定的(使用非稳定的通信链路),所以知道请求是否失败对我来说很重要。所以默认值(T)是不够的。@请注意,您是对的,使用
default(T)
比显式设置
null
要好。此解决方案唯一的缺点是它将类型检查从编译时转移到运行时。@NicolasVoron如果您使用上述检查,传递不可为null的
T
将触发异常,确保“世界末日”提前到来。一旦您通过了该检查点,您就可以自由地设置
默认值(T)
,该值总是
null
@NicolasVoron如果您希望它是防白痴的,那么只需使用两个方法名称;就这么简单。如果你假设一个特别愚蠢或恶意的用户,你不应该寻找任何其他的解决方案。好主意。遗憾的是,它不能以这种方式排列(等待
选项
,然后获取
选项。值
),因为这个调用必须重复多次。@NicolasVoron:如果
选项,你只能获得
选项。值
。@NicolasVoron:重复调用多次有什么问题吗?我不太明白。嗯。。。正在尝试比较
int?i=等待请求值(命令请求命令)
选项oi=等待请求值(命令请求命令);智力?i=(oi!=null)?oi.Value:null
。不是真正的问题,只是一句话我认为这绝对是正确的方法(扩展方法恢复了包装所失去的灵活性)。非常感谢Jordão!:)这就是p
static Task<T> RequestValue1<T>(Command requestCommand, out bool Success);
static Task<T> RequestValue1<T>(Command requestCommand, out ResultStatus Status);