我将lambda表达式设置为事件的事件处理程序
proxy.SomeEvent += (sender, e) => { doSomething(); };
但在调试时,我发现doSomething()执行了两次,因为不知何故,上面的事件赋值语句执行了两遍。
所以我想在调用事件分配语句之前检查proxy.SomeEvent
是否为null,比如:
if(proxy.SomeEvent == null)
{
proxy.SomeEvent += (sender, e)=> { doSomething(); };
}
但是我得到了一个编译器错误事件"代理"。SomeEvent’只能出现在+=或-=的左侧
由于-=
运算符不可能删除lambda表达式事件处理程序,是否有其他方法可以让我检查是否已经分配了事件?
没有(标准)方法来"检查"事件处理程序的内容。
只有的有效表格(用于外部访问)为:
obj.Event += Handler;
obj.Event -= Handler;
当在类外访问它时,它不允许在事件上调用任何方法,也不支持任何其他运算符。
但是,如果您以这样一种方式编写它,即保留原始处理程序,那么您可以提前将其删除。
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;
我并不是说这是最好的/好的方法(例如,为什么允许为"同一"处理程序多次分配处理程序?),但这是我偶尔使用的一种方法。
快乐的编码。
为了避免赋值语句被执行两次(并处理多个线程):
class foo {
bool isAssigned;
void someMethod()
{
if (!isAssigned)
{
lock (this)
{
if (!isAssigned) proxy.SomeEvent += ...;
isAssigned = true;
}
}
}
您的具体问题是如何检查lambda是否已经注册,以避免注册两次。在过去的I中,我没有声明一个单独的方法(它将支持"-="),我只是在订阅事件之前将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,以根据闭包输入值确定事件订阅是否相同。这允许您安全地订阅闭包类的一个实例,并在以后的某个时间点取消订阅/重新订阅另一个实例。