我正在寻找使用lamba表达式来允许事件以强类型方式连接,但是在中间有一个监听器,例如给定以下类
class Producer { public event EventHandler MyEvent; } class Consumer { public void MyHandler(object sender, EventArgs e) { /* ... */ } } class Listener { public static void WireUp( Expression > expr) { /* ... */ } }
事件将被连线为:
Listener.WireUp((p, c) => p.MyEvent += c.MyHandler);
但是这会给编译器错误:
CS0832:表达式树可能不包含赋值运算符
现在起初这似乎是合理的,特别是在阅读了关于为什么表达式树不能包含赋值的解释之后.但是,尽管有C#语法,但+=
它不是赋值,它是对Producer::add_MyEvent
方法的调用,正如我们可以从CIL中看到的那样,如果我们只是正常连接事件:
L_0001: newobj instance void LambdaEvents.Producer::.ctor() L_0007: newobj instance void LambdaEvents.Consumer::.ctor() L_000f: ldftn instance void LambdaEvents.Consumer::MyHandler(object, class [mscorlib]System.EventArgs) L_0015: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int) L_001a: callvirt instance void LambdaEvents.Producer::add_MyEvent(class [mscorlib]System.EventHandler)
因此,我认为这是一个编译器错误,因为它抱怨不允许分配,但没有任何分配,只是一个方法调用.或者我错过了什么......?
编辑:
请注意,问题是"此行为是编译器错误吗?".对不起,如果我不清楚我在问什么.
编辑2
在阅读了Inferis的回答之后,他说"在那一点上+ =被认为是赋值"这确实有意义,因为此时编译器可能无法知道它将变成CIL.
但是我不允许编写显式方法调用表单:
Listener.WireUp( (p, c) => p.add_MyEvent(new EventHandler(c.MyHandler)));
得到:
CS0571:'Producer.MyEvent.add':无法显式调用operator或accessor
所以,我想这个问题归结为+=
C#事件的实际意义.这是否意味着"为此事件调用add方法"或它是否意味着"以尚未定义的方式添加到此事件".如果它是前者,那么在我看来这是一个编译器错误,而如果它是后者那么它有点不直观但可以说不是一个bug.思考?
在7.16.3节的规范中,+ =和 - =运算符被称为"事件赋值",它肯定使它听起来像赋值运算符.它在7.16节("赋值运算符")中的事实是一个非常大的暗示:)从这个角度来看,编译器错误是有道理的.
然而,我同意这是过于严格,因为它是完全有可能的表达式树来表示由lambda表达式给定的功能.
我怀疑语言设计师采用"稍微限制但操作员描述更一致"的方法,牺牲了这样的情况,我担心.