C# 为什么可以';编译器没有发现这个lambda是一个委托吗?
考虑一下这个小程序C# 为什么可以';编译器没有发现这个lambda是一个委托吗?,c#,.net,lambda,delegates,C#,.net,Lambda,Delegates,考虑一下这个小程序 public class Program { public static void Main() { // the first path compiles RunAction(() => { }); // the second path does not compile RunDelegate(() => {}); } private static void Run
public class Program
{
public static void Main()
{
// the first path compiles
RunAction(() => { });
// the second path does not compile
RunDelegate(() => {});
}
private static void RunAction(Action run) => RunDelegate(run);
private static void RunDelegate(Delegate run) { }
}
第一条路径编译并暗示
()=>{}
lambda是一个操作
操作
是一个委托
,并且()=>{}
lambda是委托
public class Program2
{
public static void Main()
{
// both of these comple
AcceptPerson(new Programmer());
AcceptAnimal(new Programmer());
}
private static void AcceptPerson(Person p) => AcceptAnimal(p);
private static void AcceptAnimal(Animal a) { }
}
public class Programmer : Person { }
public class Person : Animal { }
public class Animal { }
匿名函数(如()=>{}
)没有“默认”委托类型。这样的表达式可以隐式转换为任何具体的委托类型,即右签名和返回类型(根据各种自然变化规则)
您可以有许多匹配的委托类型:
namespace TestFramework
{
public delegate void TestDelegate();
}
namespace System
{
public delegate void Action();
}
namespace System.Threading
{
public delegate void ThreadStart();
}
...
在所有这些可能的具体委托类型中(每种类型都作为抽象的System.delegate
作为其(间接的)基类),没有首选的委托类型
表达式()=>{}
之间存在隐式转换:
TestDelegate f = () => { };
Action g = () => { };
ThreadStart h = () => { };
...
由于隐式转换,调用RunAction(()=>{})代码>工作
但是使用RunDelegate(()=>{})代码>不知道要使用什么具体的委托类型。您必须执行以下操作之一:
RunDelegate((TestDelegate)(() => { }));
RunDelegate((Action)(() => { }));
RunDelegate((ThreadStart)(() => { }));
...
对你的问题的评论是正确的
与此相关的事实是,这不会编译:
var f = () => { }; // illegal, shows that '() => { }' does NOT have type System.Action
你不能使用像myBool这样的子表达式?(()=>{}):null
,依此类推。不幸的是,当您将委托
作为一种类型处理时,编译器必须推断出一种实际的委托类型以用于委托,并且可能有许多可能的委托类型可用于实际的代码。编译器只是简单地说“不,不能那样做”,因为这是语言设计者在本例中决定要做的。假设(1)是不正确的()=>{}
不是一个操作
,它在代码中的某个地方没有类型声明操作
,允许编译器进行推理。@spender Right。我现在回忆起Action run=()=>{}代码>和运行操作(()=>{})
都将lambda声明为操作
。在第二种情况下,这就不那么直观了。具体来说,问题不是编译器无法确定您正在处理的是委托
,而是编译器不理解您正在处理的是哪个特定委托,它们都是从Delegate
派生的实例。一个有趣的决定是var x=new{}
适用于匿名对象,但var y=()=>{}
不适用于lambdas。令我惊讶的是,编译器没有发现后者是一个操作
。另一个不对称性是,我们可以强制转换lambda,但不能强制转换匿名对象。