最近我很惊讶 C# 中的一段特定语法以一种“神奇”的方式工作。此语法具有多个重载,仅通过
Action<T>
或 Func<T>
参数中的泛型类型进行区分。这可能是由于更熟悉 C++ 语法而产生的偏差,但令我惊讶的是,msbuild 能够仅基于 lambda 表达式正确选择重载,甚至不需要指定 lambda 参数的类型。
using System;
namespace Test1;
internal class Program
{
public static void Main(string[] args)
{
// Picks overload #1 - somehow knows that x must be an int.
Accept(x => x = 1);
// Picks overload #2 - somehow knows that x must be a string.
Accept(x => x.ToLower());
}
// Overload #1
private static void Accept(Action<int> action) => action(0);
// Overload #2
private static void Accept(Action<string> action) => action("abc");
}
我很有趣的是,如何将
x => x = 1
正确推断为Overload #1
,以及如何将x => x.ToLower()
正确推断为Overload #2
。我本以为我必须明确 lambda 表达式的类型。例如,Accept((int x) => x = 1);
和 Accept((string x) => x.ToLower());
。
C# 标准或其他地方是否有任何内容能够解释这是如何发生的,以及这种推断可能在什么条件或规则下发生?
类型是根据用法推断的。虽然 int 可以转换为字符串,但它不能隐式完成,因此第一个选项是通过兼容赋值推断的。 int 也没有 .ToLower() 扩展方法,因此第二个选项可以推断为字符串类型。另一方面,如果您的类型更加模糊,您会收到错误。
public static void Main(string[] args)
{
// Produces Error CS0121
Accept(x => x = 1);
}
// Overload #1
private static void Accept(Action<int> action) => action(0);
// Overload #2
private static void Accept(Action<long> action) => action(1L);