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:在哪里上课
{
//随便
}
我希望我的两个方法具有相同的名称这可能吗?
我的问题:
- 我必须编写两种不同的方法,因为返回类型是
ifnull
是值类型,而T
ifT
的实例是引用类型李>T
不允许ref/out,因此如果没有类型为async
的方法参数,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 ont
:“出于方法重载的目的,方法的返回类型不是方法签名的一部分。“-但是给另一个输入参数来区分如何?如果不是相同的名称,您可以给它们更好的名称,例如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);