为什么在没有 return 值的 lambda 中添加 throw 会被推断为 Func<T> 而不是 Action?
Why does adding throw inside a lambda without a return value get inferred as a Func<T> and not as Action?
我 运行 遇到一个问题,我正在编写的库的一些测试代码由于调用不明确而无法编译,但用法对我来说似乎很清楚。经过进一步调查,我发现在没有 return 值的 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>
因为抛出它不能推断出任何 return 类型......但为什么不能呢?为什么它会推断并调用具体的 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
在上面的人为示例中研究这些仍然没有多大意义,因为这些错误有点自相矛盾。如果编译器可以弄清楚它是 returning string
并且不能转换为 int
,为什么它会对不同的 return 类型或空委托 return值?
谁能解释一下为什么编译器似乎无法理解我的意图?这是 C# 限制还是我没有看到歧义?
正如@Servy 在重复的 link
中所述
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!");}
适合 Action
或 Func<int>
。而且,“当参数是匿名方法时,它总是更喜欢委托(或表达式)具有 return 值的重载,而不是没有 return 值的重载" 然后选择 Func<int>
。
关于其他例外情况:
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
。在测试中,你调用了下面的匿名方法 returns a string
但它应该 return int
因为你的 Func<int>
returns int
:
foo.Method(() =>
{
if (false)
{
throw new Exception("Foo!");
}
return "foo";
});
为了避免异常,你应该 return 一个 int
:
foo.Method(() =>
{
if (false)
{
throw new Exception("Foo!");
}
return 1;
});
参考资料
我 运行 遇到一个问题,我正在编写的库的一些测试代码由于调用不明确而无法编译,但用法对我来说似乎很清楚。经过进一步调查,我发现在没有 return 值的 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>
因为抛出它不能推断出任何 return 类型......但为什么不能呢?为什么它会推断并调用具体的 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
在上面的人为示例中研究这些仍然没有多大意义,因为这些错误有点自相矛盾。如果编译器可以弄清楚它是 returning string
并且不能转换为 int
,为什么它会对不同的 return 类型或空委托 return值?
谁能解释一下为什么编译器似乎无法理解我的意图?这是 C# 限制还是我没有看到歧义?
正如@Servy 在重复的 link
中所述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!");}
适合 Action
或 Func<int>
。而且,“当参数是匿名方法时,它总是更喜欢委托(或表达式)具有 return 值的重载,而不是没有 return 值的重载" 然后选择 Func<int>
。
关于其他例外情况:
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
。在测试中,你调用了下面的匿名方法 returns a string
但它应该 return int
因为你的 Func<int>
returns int
:
foo.Method(() =>
{
if (false)
{
throw new Exception("Foo!");
}
return "foo";
});
为了避免异常,你应该 return 一个 int
:
foo.Method(() =>
{
if (false)
{
throw new Exception("Foo!");
}
return 1;
});