[英]When did C# get this “SFINAE-like” overload resolution of Action<..> parameters, and what is it called?
考虑以下代码,其中 C# 可以根据提供的隐式类型 Action<T>来消除重载的歧义,其中 T 是基于操作代码的 [互斥] 类型有效性派生的。
我很惊喜,意识到我已经“不假思索地依赖这种方便的行为”有一段时间了,尽管它要求编译器检查 Action 中的代码以及有效的目标站点类型。 通常必须先解析类型,然后才能在目标表达式中使用它。
这种行为是什么时候引入的? 这种类型推断的正确名称是什么? 有哪些限制和已知的极端情况? 哪些文档链接(或规范中的部分)涵盖了该行为?
static void WithAction(Action<string> s) {
Console.WriteLine("string action");
s("string");
}
static void WithAction(Action<int> i) {
Console.WriteLine("int action");
i(1);
}
void Main()
{
// Compiler has to INFER that this is an Action<string>
// where the target type must be in {Action<string>, Action<int>}
// (int does not have a Length property)
WithAction(s => Console.WriteLine(s.Length == 1));
// Ditto, except compiler infers Action<int>.
// (there is no string == int operator overload)
WithAction(i => Console.WriteLine(i == 1));
// compiler error
// CS0121 The call is ambiguous between the following methods or properties:
// 'UserQuery.WithAction(Action<string>)' and 'UserQuery.WithAction(Action<int>)'
// (there is both int == int and string == string!)
// WithAction(z => Console.WriteLine(z == z));
}
该代码在 LINQPad 5 中运行并生成以下 output:
string action
False
int action
True
C# 规范在匿名 Function 转换中涵盖了这一点。
匿名函数包括旧的delegate (...) {... }
语法的 lambda 表达式。
在该部分中,它说匿名 function F
可以转换为D
委托类型,前提是:
如果
F
的主体是一个表达式,并且D
具有void
返回类型或F
是async
且D
具有返回类型Task
,则当F
的每个参数被赋予D
中相应参数的类型时,F
的主体是允许作为 statement_expression 的有效表达式 (wrt Expressions )。
本质上,关键是转换仅在“ F
的主体是有效(语句)表达式”时才有效。 如果s
是int
,则Console.WriteLine(s.Length == 1)
不是有效的语句表达式,因此没有转换。
当编译器在重载决议期间考虑适用的 function 成员时,根本不考虑采取Action<int>
的重载,因为没有(隐式)转换为Action<int>
。
从这适用于所有匿名函数的事实来看,此功能可能并不新鲜。 它可能与delegate (...) {... }
一样古老。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.