【发布时间】:2020-06-07 02:14:07
【问题描述】:
我遇到了一个问题,即我正在编写的库的某些测试代码由于调用不明确而无法编译,但我的用法似乎很清楚。经过进一步调查,我发现在没有返回值的 lambda 中添加throw 似乎被推断为任何T 的Func<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 委托感到不安呢?
谁能解释为什么编译器似乎无法理解我的意图?这是 C# 限制还是我没有看到歧义?
【问题讨论】:
-
Func<string>错误的发生是因为有两个重载并且它们都不接受返回字符串的函数。前两个错误:编译器解释了为什么它无法解决采用Func<int>的重载。第三个错误:编译器解释了为什么它无法解决采用Action的重载。 -
您是否尝试过检查代码生成的 IL?
-
@AluanHaddad 我个人理解这些错误,但是当它们一起出现时,它们似乎相互矛盾。如果第一个错误为真,那么编译器似乎将类型推断为
Func<string>,这使得第三个错误令人困惑,因为它暗示它已将 lambda 推断为返回void的void。此外,孤立的第二个错误似乎很奇怪,只有一种返回类型。为什么添加throw会让编译器认为有多种返回类型? -
当编译器不知道如何推断参数时,它会显示与它们相关的所有错误,以便不区分另一个。我同意,这里的分析器可以改进以将错误合并为一个:
Cannot infer lambda expression argument from usage. Did you mean Action or Func<int>? -
@silkfire 谢谢你的澄清,这就是我的意思。
标签: c# lambda action type-inference func