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)
答案 0 :(得分:4)
编译器如何从LAMBDA表达式推断出委托类型?
从根本上说,它没有。
编译器从名为QueueUserWorkItem
的方法组中的可用重载推断出委托类型。只有两个重载,只有一个有两个参数,并且两个重载都使用委托类型WaitCallback
。
因此,委托类型的为WaitCallback
。通过这个确定,编译器可以将lambda表达式编译为匿名方法,并实例化为QueueUserWorkItem()
方法的参数,调用必要的委托对象来调用该匿名方法。
在更复杂的情况下,编译器必须执行一些分析以确定最好的"匹配重载,并且该分析可能涉及lambda表达式,以至于它可以消除基于lambda表达式的重载可能性。
但编译器在任何时候都不会以lambda表达式开头并直接转到委托类型。对于要转换为委托实例的lambda表达式,需要为lambda表达式设置一些其他上下文来确定所需的委托类型,例如分配给类型变量,显式转换或(如本例中)a方法重载,其中lambda表达式用于的参数具有与lambda表达式兼容的特定委托类型。
请注意,泛型方法仍有类型推断,其中lambda用于推断类型参数。 Eric Lippert's comment清楚地解释了这一点:
在某些情况下,编译器必须从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来推断类型参数,但编译器仍然需要知道开放泛型类型的上下文。
有关详细信息,请阅读the C# specification。它将详细说明如何执行重载决策以及管理它并将lambda表达式与类型匹配的规则。
补充阅读:
.Net lambda expression— where did this parameter come from?
Why can't an anonymous method be assigned to var?
Why can't the compiler tell the better conversion target in this overload resolution case? (covariance)
Convert this delegate to an anonymous method or lambda
不巧的是,前三个包括Eric Lippert撰写的关于该主题和相关问题的出色讨论,他曾经在Visual Studio C#编译器和语言设计团队工作。