我将lambda表达式设置为事件的事件处理程序
proxy.SomeEvent += (sender, e) => { doSomething(); };
但是在调试时我发现doSomething()被执行了两次,因为上面的事件赋值语句被执行了两次。
所以我想在调用事件赋值语句之前检查proxy.SomeEvent
是否为null,如:
if(proxy.SomeEvent == null)
{
proxy.SomeEvent += (sender, e)=> { doSomething(); };
}
但我收到编译错误事件'Proxy.SomeEvent'只能出现在+ =或 - = 的左侧
由于-=
运算符无法删除lambda表达式事件处理程序,是否有其他方法可以检查是否已分配事件?
答案 0 :(得分:3)
没有(标准)方法来“检查”事件处理程序的内容。
仅有效表单(用于外部访问)是:
obj.Event += Handler;
obj.Event -= Handler;
当它在类外部访问时,它不允许在Event上调用任何方法,也不支持任何其他运算符。
但是,如果您以保留原始处理程序的方式编写它,那么您可以在事先删除它。
public Handler(object sender, EventArgs) {
...
}
// remove if already added (does nothing if it was not added)
// there is no (standard) way to check if it was added so this
// is just a pre-emptive remove
proxy.SomeEvent -= Handler;
// and add the handler
proxy.SomeEvent += Handler;
我不是说这是最好/最好的方法(例如,为什么处理程序允许被多次分配给“同一个”处理程序?),但这是一种方法我有时使用过。
快乐的编码。
答案 1 :(得分:2)
为避免分配语句被执行两次(并处理多个步骤):
class foo {
bool isAssigned;
void someMethod()
{
if (!isAssigned)
{
lock (this)
{
if (!isAssigned) proxy.SomeEvent += ...;
isAssigned = true;
}
}
}
答案 2 :(得分:1)
您的具体问题是如何检查您的lambda是否已经注册,以避免两次注册。在过去,我没有声明一个单独的方法(支持“ - =”),我只是在订阅事件之前将lambda分配给局部变量。
public class SomeOtherClass
{
public void ResponseToSomeEvent()
{
var proxy = new Proxy();
// Assign the lambda to a local variable
EventHandler doSomething = (sender, e) => Console.WriteLine("Just Once");
// Subscribe to event
proxy.SomeEvent += doSomething;
proxy.Raise();
// Unsubscribe and resubscribe to event
proxy.SomeEvent -= doSomething;
proxy.SomeEvent += doSomething;
proxy.Raise();
}
}
public class Proxy
{
public event EventHandler SomeEvent;
public void Raise()
{
Console.WriteLine("Raise");
SomeEvent(this, EventArgs.Empty);
}
}
结果如预期的那样,lambda仅在每次引发事件时调用一次,因为 - =实际上能够删除订阅,因为您能够提供要删除的事件处理程序。
但是,在更复杂的场景中,您可能正在使用lambda来执行闭包,并且由于代码路径,您无法轻松维护对用于订阅事件的原始lambda的引用。如果您的情况很复杂,我建议创建一个具体的闭包类(类似于C#编译器所做的)并使用闭包类实例上的方法订阅该事件。然后,您需要在闭包类上重写equals,以根据闭包输入值确定事件订阅是否相同。这允许您安全地订阅闭包类的一个实例,并在稍后的某个时候使用不同的实例取消订阅/重新订阅。