编译器如何从LAMBDA表达式推断委托类型
本文关键字:类型 表达式 LAMBDA 编译器 | 更新日期: 2023-09-27 17:54:01
示例代码
int id = 123;
ThreadPool.QueueUserWorkItem(state => ThreadEntryPoint((int)state), id);
public void ThreadEntryPoint(int uniqueId)
{
Console.WriteLine("uniqueId=" + uniqueId);
}
从提供的LAMBDA表达式,编译器如何知道它需要创建QueueUserWorkItem(WaitCallback, Object)
的实例?
更具体地说:我理解它是在推断委托类型。我不明白的是什么决策树(从高层)是通过选择正确的委托类型实例化?
引用- ThreadPool。QueueUserWorkItem
-
ThreadPool.QueueUserWorkItem(WaitCallback, Object)
-
- WaitCallback委托
-
QueueUserWorkItem(WaitCallback, Object)
-
QueueUserWorkItem(WaitCallback)
-
编译器如何从LAMBDA表达式推断委托类型?
基本上没有。
编译器从名为QueueUserWorkItem
的方法组中可用的重载推断委托类型。只有两个重载,只有一个有两个参数,两个重载都使用委托类型WaitCallback
。
WaitCallback
。确定了这一点后,编译器就可以将lambda表达式编译为一个匿名方法,并实例化为QueueUserWorkItem()
方法的参数,调用必要的委托对象来调用该匿名方法。
在更复杂的场景中,编译器将不得不执行一些分析来确定重载的"最佳"匹配,并且该分析可能涉及lambda表达式,从而可以基于lambda表达式消除重载的可能性。
但是编译器不会从lambda表达式开始,直接转到委托类型。要将lambda表达式转换为委托实例,需要为lambda表达式提供一些其他上下文,以确定所需的委托类型,例如对类型化变量的赋值、显式强制转换,或者(如本例)方法重载,其中使用lambda表达式的参数具有与lambda表达式兼容的特定委托类型。
请注意,对于泛型方法仍然存在类型推断,其中lambda用于推断类型参数。Eric Lippert的评论清楚地解释了这一点:
在某些情况下,编译器必须从lambda中推断构造的委托类型。例如,如果我们有
M<A, R>(Func<A, R> f)
和M((string x) => x.Length)
,那么编译器将首先从lambda形参中推断出Func<string, something>
,然后从lambda形参的体中推断出Func<string, int>
。
我的观点是编译器不会从头开始推断Func<T, TResult>
。正如Eric指出的那样,编译器确实使用lambda来推断类型参数,但是编译器仍然需要上下文,其中开放泛型类型是已知的。
要了解更多细节,您应该阅读c#规范。它将详细说明重载解析是如何执行的,以及控制该解析和将lambda表达式与类型匹配的规则。
额外的阅读:
.Net lambda表达式——这个参数是从哪里来的?
为什么不能将匿名方法赋值给var?
在这种重载解析的情况下,为什么编译器不能告诉更好的转换目标?(协方差)
将此委托转换为匿名方法或lambda
并非巧合的是,前三本书包含了Eric Lippert所写的关于该主题和相关问题的精彩讨论,Eric Lippert曾在Visual Studio c#编译器和语言设计团队工作。