开发者

C# event null check (from another class)

I set an lambda expression as a event handler to a event

proxy.SomeEvent += (sender, e) => { doSomething(); };

But when debugging I found doSomething() was executed twice because somehow the above event assignment statement was executed twice.

So I want check whether the proxy.SomeEvent is null before calling the event assignment statement,like:

if(proxy.SomeEvent 开发者_JAVA百科== null)
{
    proxy.SomeEvent += (sender, e)=> { doSomething(); };
}

But I get a compiler error The event 'Proxy.SomeEvent' can only appear on the left hand side of += or -=

Since it is not possible to remove a lambda expression event handler by the -= operator, is there other way which enables me to check whether an event has already been assigned?


There is no (standard) way to "inspect" what an event handler has.

The only valid forms (for external access) are:

obj.Event += Handler;
obj.Event -= Handler;

It when accessed outside the class it does not allow any method invoked upon the Event nor does it support any other operators.

However, if you write it in such a way that you keep the original handler then you can remove it before-hand.

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;

I'm not saying this is the best/a good way (e.g. why is the handler allowed to be assigned multiple times for "the same" handler?), but it is one approach I have used on occasion.

Happy coding.


To avoid the assignment statement being executed twice (and coping with multiple treads):

class foo {
   bool isAssigned;

   void someMethod()
   {
      if (!isAssigned)
      {
        lock (this)
        {
            if (!isAssigned) proxy.SomeEvent += ...;
            isAssigned = true;
        }
      }
   }


Your specific question was how to check to see if your lambda was already registered in order to avoid registering it twice. In the past I where I did not what to declare a separate method (which would support "-="), I just assigned the lambda to a local variable before subscribing to the event.

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);
    }
}

The result is as expected, the lambda is only invoked once each time the event is raised, because the -= is effectively able to remove the subscription since you were able to provide the event handler to remove.

However, in more complex scenarios you may be using a lambda to perform a closure, and due to code paths you cannot easily maintain a reference to the original lambda that you used to subscribe to the event. If your case is this complex, I recommend creating a concrete closure class (similar to what the C# compiler does) and subscribe to the event using a method on an instance of your closure class. You will then need to override equals on your closure class to determine that the event subscription is the same based on the closure input values. This allows you to safely subscribe with one instance of your closure class and unsubscribe/resubscribe with a different instance at some later point.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜