c# - 为什么在没有返回值的 lambda 中添加 throw 会被推断为 Func<T> 而不是 Action?

标签 c# lambda action type-inference func

这个问题在这里已经有了答案:





How can I force a throw to be a statement and not an expression (in a lambda expression)?

(4 个回答)


2年前关闭。




我遇到了一个问题,我正在编写的库的一些测试代码由于调用不明确而无法编译,但我的用法似乎很清楚。经过进一步调查,我发现添加 throw在没有返回值的 lambda 中似乎被推断为 Func<T>任何T而不是 Action正如我所料。

下面的人为示例(可以粘贴到 .NET Fiddle 中)

using System;

public class Program
{
    class Foo
    {

        public void Method(Action action)
        {
            Console.WriteLine("Method A: " + action.GetType());
        }

        public void Method(Func<int> func)
        {
            Console.WriteLine("Method B: " + func.GetType());
        }

        /* // second call to Method becomes ambiguous if this is commented out.
        public void Method(Func<bool> func)
        {
            Console.WriteLine(func.GetType());
        }
        */

    }

    public static void Main()
    {
        var foo = new Foo();
        foo.Method(() => { });
        foo.Method(() => { throw new Exception("Foo!"); });
    }
}

这导致
Method A: System.Action
Method B: System.Func`1[System.Int32]

也许它假设 Func<object>因为抛出它不能推断出任何返回类型......但为什么不能呢?为什么它会推断并调用具体的 Func<int> ?

此外,如果我尝试创建隐式 Func<string>像这样:
foo.Method(() => 
{ 
    if (false) 
    { 
        throw new Exception("Foo!");
    }
    return "foo";
});

我得到了三个我以前没有遇到过的单独的编译错误:
Compilation error (line 38, col 16): Cannot implicitly convert type 'string' to 'int'
Compilation error (line 38, col 16): Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type
Compilation error (line 38, col 9): Anonymous function converted to a void returning delegate cannot return a value

在上面的人为示例中研究这些仍然没有多大意义,因为这些错误有点自相矛盾。如果编译器可以确定它正在返回 string并且无法转换为 int ,为什么它对不同的返回类型或返回值的 void 委托(delegate)感到不安?

谁能解释为什么编译器似乎难以理解我的意图?这是 C# 限制还是我没有看到歧义?

最佳答案

正如@Servy 在重复链接中所述

The rules for determining which overload is called are spelled out in section 7.5.3.3 of the C# specs. Specifically, when the parameter is an anonymous method, it will always prefer the overload who's delegate (or expression) has a return value over one that has no return value. This will be true whether it's a statement lambda or expression lambda; it applies to any form of anonymous function.


在下面的代码中:
var foo = new Foo();
foo.Method(() => { });
foo.Method(() => { throw new Exception("Foo!"); }); 
因为() => { throw new Exception("Foo!");}适合 ActionFunc<int> .而且,“当参数是匿名方法时,它总是更喜欢委托(delegate)(或表达式)有返回值的重载而不是没有返回值的重载”然后 Func<int>被选中。
关于其他异常(exception):
Compilation error (line 38, col 16): Cannot implicitly convert type 'string' to 'int'
Compilation error (line 38, col 16): Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type
Compilation error (line 38, col 9): Anonymous function converted to a void returning delegate cannot return a value 
上述异常是因为 bad output types .在测试中,您调用了以下匿名方法,该方法返回 string但它应该返回 int因为你的Func<int>返回 int :
foo.Method(() => 
{ 
    if (false) 
    { 
        throw new Exception("Foo!");
    }
    return "foo";
});
为避免异常,您应该返回 int :
foo.Method(() => 
{ 
    if (false) 
    { 
        throw new Exception("Foo!");
    }
    return 1;
});
引用
  • Overload Resolution
  • 关于c# - 为什么在没有返回值的 lambda 中添加 throw 会被推断为 Func<T> 而不是 Action?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60359145/

    相关文章:

    c# - chrome升级到63版本后Selenium ChromeDriver异常

    c# - 在无限循环性能中声明变量类型?

    c# - 对 IEnumerable 的替换、插入、删除操作

    javascript - 如何对不同的选择选项设置不同的操作?

    asp.net-mvc - 将类对象从一个 Controller 操作传递到 ASP.net MVC 4 中的不同 Controller 操作

    C# 文件和目录迭代,可以同时进行吗?

    c# - 异步 lambda 中的参数

    lambda - 为什么 Java Lambda 类型推断仅处理具有唯一参数的方法?

    c++ - 如何使用 lambda 作为 std::unique_ptr 的删除器?

    java - 如何在java中使用selenium查找该字段是否不可编辑