【发布时间】:2009-02-19 11:55:26
【问题描述】:
我正在考虑使用 Lamba 表达式以允许以强类型方式连接事件,但中间有一个侦听器,例如给定以下类
class Producer
{
public event EventHandler MyEvent;
}
class Consumer
{
public void MyHandler(object sender, EventArgs e) { /* ... */ }
}
class Listener
{
public static void WireUp<TProducer, TConsumer>(
Expression<Action<TProducer, TConsumer>> expr) { /* ... */ }
}
一个事件将被连接为:
Listener.WireUp<Producer, Consumer>((p, c) => p.MyEvent += c.MyHandler);
但是这会导致编译器错误:
CS0832:表达式树可能不包含赋值运算符
现在这似乎是合理的,尤其是在reading the explanation about why expression trees cannot contain assignments 之后。然而,尽管有 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<Producer, Consumer>(
(p, c) => p.add_MyEvent(new EventHandler(c.MyHandler)));
给予:
CS0571:“Producer.MyEvent.add”:无法显式调用运算符或访问器
所以,我想问题归结为+= 在 C# 事件上下文中的实际含义。它的意思是“为此事件调用 add 方法”还是“以尚未定义的方式添加到该事件”。如果是前者,那么这在我看来是一个编译器错误,而如果是后者,那么它有点不直观,但可以说不是一个错误。想法?
【问题讨论】:
-
+= 表示“调用给定事件的事件访问器”。我认为这不是一个错误,而是一个有点烦人且可以说是不必要的限制。
标签: c# compiler-construction lambda compiler-errors