Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.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# “的λ”;x=>;{throw..}";推断为匹配Func<;T、 任务>;在重载方法中?_C#_.net_Lambda_Overloading_Type Inference - Fatal编程技术网

C# “的λ”;x=>;{throw..}";推断为匹配Func<;T、 任务>;在重载方法中?

C# “的λ”;x=>;{throw..}";推断为匹配Func<;T、 任务>;在重载方法中?,c#,.net,lambda,overloading,type-inference,C#,.net,Lambda,Overloading,Type Inference,我不明白为什么C#最终在以下LINQPad代码中执行了错误的扩展方法: void Main() { // Actual: Sync Action "Expected: Sync Action".Run(x => { x.Dump(); }); // Actual: Async Task "Expected: Async Task".Run(async x => { await System.Threading.Tasks.Task.Run(() =&

我不明白为什么C#最终在以下LINQPad代码中执行了错误的扩展方法:

void Main()
{
    // Actual: Sync Action
    "Expected: Sync Action".Run(x => { x.Dump(); });

    // Actual: Async Task
    "Expected: Async Task".Run(async x => { await System.Threading.Tasks.Task.Run(() => x.Dump()); });

    // Actual: Async Task!!
    "Expected: Sync Action".Run(x => { throw new Exception("Meh"); });
}

static class Extensions
{
    public static void Run<T>(this T instance, Action<T> action)
    {
        "Actual: Sync Action".Dump();
        action(instance);
    }

    public static void Run<T>(this T instance, Func<T, System.Threading.Tasks.Task> func)
    {
        "Actual: Async Task".Dump();
        func(instance).Wait();
    }
}
void Main()
{
//实际:同步操作
“预期:同步操作”。运行(x=>{x.Dump();});
//实际:异步任务
“应为:异步任务”。运行(异步x=>{await System.Threading.Tasks.Task.Run(()=>x.Dump());});
//实际:异步任务!!
“应为:同步操作”。运行(x=>{throw new Exception(“Meh”);});
}
静态类扩展
{
公共静态无效运行(此T实例,操作)
{
“实际:同步操作”。转储();
行动(实例);
}
公共静态无效运行(此T实例,Func Func)
{
“实际:异步任务”.Dump();
func(instance.Wait();
}
}
为什么编译器认为lambda在这里返回任务


我希望在对Run()的第三次调用中看到“Actual:Sync Action”,因为lambda中没有任何内容表明这是一个Func返回任务。

这只是一个重载解决问题。显然,lambda
x=>{throw new Exception(“Meh”);}
可以转换为
操作或
函数(以及与此问题无关的许多其他委托类型)。在这种情况下,C#的重载解析规则更倾向于后者

这里有一个更具代表性的例子:

void Main()
{
    // Output: Func<T, int>
    "Test".WhatsThis(x => { throw new Exception("Meh"); });
}

static class Extensions
{
    public static void WhatsThis<T>(this T dummy, Action<T> action)
    {
       "Action<T>".Dump();
    }
    public static void WhatsThis<T>(this T dummy, Func<T, int> func)
    {
       "Func<T, int>".Dump();
    }
}
void Main()
{
//输出:Func
“Test”.whatstthis(x=>{throw new Exception(“Meh”);});
}
静态类扩展
{
公共静态无效WhatsThis(此T虚拟,动作)
{
“Action.Dump();
}
公共静态无效WhatsThis(此T虚拟,Func Func)
{
“Func.Dump();
}
}
至于为什么会出现这种情况,我不是100%确定,但随便看看下面的例子,我就会发现以下可能的解释(我的重点):

7.5.3过载分辨率

[……]

7.5.3.3更好地从表达式转换

给定从表达式E转换为类型T1的隐式转换C1,以及从表达式E转换为类型T2的隐式转换C2,如果至少满足以下条件之一,则C1比C2是更好的转换:

[……]

•E是匿名函数,T1是委托类型D1或表达式树类型
表达式
,T2是委托类型D2或表达式树 键入
Expression
,下列选项之一适用:

[……]

•D1的返回类型为Y,D2为无效返回


这是Linqpad代码。。除了Dump()扩展方法没有什么特别的。你是对的,它实际上与扩展方法无关,因为我可以用正常的重载方法进行复制。谢谢你解释可能发生的事情。在上面的第二次调用中,我显式指定了“async x=>”,这可能会提示编译器我们正在处理一个lambda返回任务。在没有async关键字的情况下,对func而不是操作使用“default”是否有意义,或者这只是一个任意选择?显然,规范认为非void返回委托在这种情况下比void委托“更好”/“更具体”。不过,它并没有说明原因。我怀疑带注释的规范可能会透露更多信息(遗憾的是,我没有副本)。如果像Eric Lippert这样的人看到这个问题,我们很可能会得到更明确的解释。@ichen:
async
关键字不会影响lambda的类型。我相信重载解析规则的目的是避免
async void
lambdas,@StephenCleary是的,这是有意义的。我还看到您评论说Microsoft故意选择Func返回任务委托而不是操作。看来解决这个问题的唯一方法是显式实例化所需的委托。