C# C什么时候得到这个的;类似SFINAE的“;操作的重载解析<&燃气轮机;参数,它叫什么?

C# C什么时候得到这个的;类似SFINAE的“;操作的重载解析<&燃气轮机;参数,它叫什么?,c#,syntax,overloading,type-inference,type-systems,C#,Syntax,Overloading,Type Inference,Type Systems,考虑以下代码,其中C#可以根据提供的隐式类型的操作消除重载的歧义,其中T是根据操作代码的[互斥]类型有效性派生的 我很惊喜,意识到我已经“依赖这种方便的行为而不去思考”一段时间了,尽管它要求编译器检查动作中的代码以及有效的目标站点类型。通常,必须先解析类型,然后才能在目标表达式中使用它 这种行为是什么时候开始的?此类型推断的正确名称是什么?有哪些限制和已知的边缘情况?哪些文档链接(或规范中的部分)涵盖了该行为 static void WithAction(Action<string>

考虑以下代码,其中C#可以根据提供的隐式类型的操作消除重载的歧义,其中T是根据操作代码的[互斥]类型有效性派生的

我很惊喜,意识到我已经“依赖这种方便的行为而不去思考”一段时间了,尽管它要求编译器检查动作中的代码以及有效的目标站点类型。通常,必须先解析类型,然后才能在目标表达式中使用它

这种行为是什么时候开始的?此类型推断的正确名称是什么?有哪些限制和已知的边缘情况?哪些文档链接(或规范中的部分)涵盖了该行为

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));
}
C#规范涵盖了这一点

匿名函数包括lambda表达式,该表达式使用旧的
委托(…){…}
语法

在该部分中,它指出匿名函数
F
可以转换为委托类型
D
,前提是:

如果
F
的主体是一个表达式,并且
D
具有
void
返回类型,或者
F
async
并且
D
具有返回类型
Task
,那么当
F
的每个参数都被赋予
D
中相应参数的类型时,
F
的主体是一个有效的表达式(wrt),可以作为语句\表达式使用

从本质上讲,这一点是转换只有在“F的主体是有效的(语句)表达式”时才有效。如果
s
int
Console.WriteLine(s.Length==1)
不是有效的语句表达式,因此没有转换

当编译器在重载解析过程中考虑适用的函数成员时,由于没有(隐式)转换到
操作
,因此不会考虑执行重载的
操作

从适用于所有匿名函数的事实来看,此功能可能不是新功能。它可能与
delegate(…){…}
一样古老,C#spec在中介绍了这一点

匿名函数包括lambda表达式,该表达式使用旧的
委托(…){…}
语法

在该部分中,它指出匿名函数
F
可以转换为委托类型
D
,前提是:

如果
F
的主体是一个表达式,并且
D
具有
void
返回类型,或者
F
async
并且
D
具有返回类型
Task
,那么当
F
的每个参数都被赋予
D
中相应参数的类型时,
F
的主体是一个有效的表达式(wrt),可以作为语句\表达式使用

从本质上讲,这一点是转换只有在“F的主体是有效的(语句)表达式”时才有效。如果
s
int
Console.WriteLine(s.Length==1)
不是有效的语句表达式,因此没有转换

当编译器在重载解析过程中考虑适用的函数成员时,由于没有(隐式)转换到
操作
,因此不会考虑执行重载的
操作


从适用于所有匿名函数的事实来看,此功能可能不是新功能。它可能与
委托(…){…}

一样古老,Jon Skeet写了一篇很好的博客文章,可能会帮助你找到一些答案:@DavidL谢谢你的链接。然而,它似乎没有涵盖这个案例。在上面的例子中,不是在
Action
(更具体)和
Action
之间决定,而是在
Action
Action
之间决定,在这两种情况下,Action必须“尝试编译”为目标类型,以查看它们是否可以匹配一个异或其他重载方法。我已经包括了非编译案例,当方法主体不足以让编译器推断操作的参数是
string
XOR
int
(因此操作必须是
Action
Action
)Jon Skeet写了一篇很棒的博客文章,可能会帮助你找到一些答案:@DavidL谢谢你的链接。然而,它似乎没有涵盖这个案例。在上面的例子中,不是在
Action
(更具体)和
Action
之间决定,而是在
Action
Action
之间决定,在这两种情况下,Action必须“尝试编译”为目标类型,以查看它们是否可以匹配一个异或其他重载方法。我已经包括了非编译案例,当方法主体不足以让编译器推断操作的参数是
string
XOR
int
(因此操作必须是
Action
Action
)时,我“最近”意识到发生了一些特殊的事情。我不在乎说我用C#多久了^_^我“最近”意识到发生了一些特别的事情。我不在乎说我用C#多久了^_^