Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.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#_Compilation_Type Inference_Overload Resolution - Fatal编程技术网

C# 带有同步和异步委托的重载解析类型推断问题

C# 带有同步和异步委托的重载解析类型推断问题,c#,compilation,type-inference,overload-resolution,C#,Compilation,Type Inference,Overload Resolution,我有两个方法Foo的重载,一个用于同步,一个用于异步委托: public static void Foo<T>(Func<T> function, List<T> list = null) { } public static void Foo<T>(Func<Task<T>> function, List<T> list = null) { } …除非我尝试显式传递null作为第二个参数: Foo(async

我有两个方法
Foo
的重载,一个用于同步,一个用于异步委托:

public static void Foo<T>(Func<T> function, List<T> list = null) { }

public static void Foo<T>(Func<Task<T>> function, List<T> list = null) { }
…除非我尝试显式传递
null
作为第二个参数:

Foo(async () => { await Task.CompletedTask; return 0;}, null); // Error CS0121
在这种情况下,我会得到以下编译错误:

以下方法或属性之间的调用不明确:
'Test.Foo(Func,List)
'Test.Foo(Func,List)

奇怪的是,
null
是这个参数的默认值

这是编译器的一个可以修复的限制,还是一个无法解决的歧义情况,除了编译错误之外,其他任何方法都无法处理

C#8、Visual Studio 16.3.9、.NET Framework 4.8、.NET Core 3.0


更新:是对这个问题的一个有用的回答。

您不能从“null”判断这是
List
还是
List
,编译器也不能这样做。这是后一种观点


而且它无法确定您的
任务
是否应该匹配
Func
Func
,而不是唯一的,因此这是不明确的。T=Task或R=T都是可能的

那么,如果省略
null
参数,为什么不会出现错误呢?不管怎样,它的默认值是
null
,所以在这种情况下我也应该得到一个错误。啊,我明白了,除了“无错误”,它还绑定到Func版本?推断出什么?Task.CompletedTask的类型为“Task”,因此它肯定不是“Task”类型,因此必须绑定到Func?正确的?我无法解释是否传递默认参数的效果。当我省略
null
时,编译器会正确推断类型为
int
。当我包含
null
时,编译器认为beyond
T是int
也有可能
T是Task
(第一个重载接受同步委托):-/是的,你有一个Func。如果删除async staff,一切都会按预期进行。异步lambda确实隐式地创建了一个任务,“异步int”的类型与任务相同。你真的认为你的第一个重载是固定的同步?不可能是任务吗?我们将要解释为什么歧义是显而易见的,我们只是不知道为什么它消失了,然后省略了第二个参数。请认真考虑编译器错误。如果您查看的重载,有两个类似于my
Foo
overloads。如果编译器不明白最好使用接受异步委托的重载,那么每次调用
任务时,我们都必须显式地编写
。运行
!重载解析发生在填充默认参数之前。必须这样做,因为对于位置参数,默认值可能完全不同,具体取决于选择的重载。一旦选择了重载,就不会有歧义(根据定义)。但是如果您提供参数值,现在编译器无法知道哪种方法重载更好,因为推理规则在返回到
T
之前就依赖
null
值。请参阅同一问题的标记副本。@PeterDuniho我仔细阅读了被称为副本的两个问题,包括Eric Lippert的冗长而详细的答案,但我不认为这些问题与我的问题重复。第一个问题涉及
params
关键字,我在问题中没有提到。这些问题都没有提到可选的论点,它们是我问题的核心。所以我仍然不知道我的问题的答案。这是编译器的一个可以修复的限制,还是一个无法解决的问题,只能通过编译错误来处理?@PeterDuniho您的评论是有道理的。你能把它扩展成一个答案吗?我发现标记的副本充分满足了需要。编译器无法在您的场景中执行重载解析,错误消息清楚地表明了这一点。解决方案是,像往常一样,并在标记副本的其他地方解释的那样,向编译器提供足够的类型信息,以便它能够。例如,将
null
强制转换为您期望的类型。或者更好,只是不指定参数。既然这是默认值,为什么要显式传递
null
。编译器没有执行重载解析,但不是因为my
params
-include方法的正常形式和扩展形式之间存在歧义。我的示例中没有
params
。这些被称为重复的问题充其量只能提供一些提示,而不是对我所观察到的错误的清晰而令人信服的解释。如果可能的话,我希望有这样一个解释作为答案,而不是评论。
Foo(async () => { await Task.CompletedTask; return 0;}, null); // Error CS0121