[英]How does compiler infer the delegate type from LAMBDA expression?
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(WaitCallback, Object)
QueueUserWorkItem(WaitCallback, Object)
QueueUserWorkItem(WaitCallback)
编译器如何从LAMBDA表达式推断出委托类型?
从根本上说,它没有。
编译器从名为QueueUserWorkItem
的方法组中的可用重载推断出委托类型。 只有两个重载,只有一个有两个参数,两个重载都使用委托类型WaitCallback
。
因此,委托类型必须是WaitCallback
。 通过这个确定,编译器然后可以将lambda表达式编译为匿名方法,并实例化为QueueUserWorkItem()
方法的参数,调用必要的委托对象来调用该匿名方法。
在更复杂的情况下,编译器必须执行一些分析以确定重载的“最佳”匹配,并且该分析可能涉及lambda表达式,以至于它可以消除基于lambda表达式的过载可能性。
但是编译器在任何时候都不会从lambda表达式开始并直接转到委托类型。 对于要转换为委托实例的lambda表达式,需要为lambda表达式设置一些其他上下文来确定所需的委托类型,例如分配给类型变量,显式转换或(如本例中)a方法重载,其中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撰写的主题和相关问题的精彩讨论,他曾经在Visual Studio C#编译器和语言设计团队工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.