Remove duplicate delegate from event

I would like to wash duplicate delegates from the event. So I wrote the following code. It is working fine. My application is a critical time application. Is there any other optimized mechansim to achieve the same. Please help me


public void FireEvent()
{
    Dictionary<Delegate, Delegate> dic = new Dictionary<Delegate, Delegate>();

    Delegate[] m = this.Paused.GetInvocationList();
    foreach (Delegate d in m)
    {
        Delegate dout;
        if (dic.TryGetValue(d, out dout))
        {                    
            continue;
        } 
        else
        {
            dic.Add(d, d);
        }
        d.DynamicInvoke(new object[2] { this, null });
    }
}
+5
source share
1 answer

The problem with the original approach

If this is a really time-critical application, I would highly recommend changing your code.

  • You create and populate a new one Dictionary<Delegate, Delegate>each time you call a method. This is pretty wasteful.
  • You use DynamicInvokeone that has lower performance than a normal call to start with.
  • object[] DynamicInvoke FireEvent.

.

, : , FireEvent, , , , ?

private HashSet<EventHandler> _pausedHandlers = new HashSet<EventHandler>();

public event EventHandler Paused
{
    add // will not add duplicates
    { _pausedHandlers.Add(value); }

    remove
    { _pausedHandlers.Remove(value); }
}

, , , .

protected void OnPaused()
{
    foreach (EventHandler handler in _pausedHandlers)
    {
        try
        {
            handler(this, EventArgs.Empty);
        }
        catch
        {
            // up to you what to do here
        }
    }
}

" "

, , , . , , , .

class Program
{
    static void Main(string[] args)
    {
        // Even though the code for FirstHandler and SecondHandler is the same,
        // they will not (nor should they) be considered equal for the purpose
        // of detecting duplicates.
        EventHandler handler1 = FirstHandler;
        EventHandler handler2 = SecondHandler;

        // Since handler2 and handler3 point to the same method, on the other
        // hand, they will (and ought to) be treated as equal.
        EventHandler handler3 = SecondHandler;

        // So this prints 'False'...
        Console.WriteLine(handler1.Equals(handler2));

        // ...and this prints 'True'.
        Console.WriteLine(handler2.Equals(handler3));

        // Now take a look at the code for SetAnonymousHandler below. The
        // method accepts an EventHandler by reference and compares it for
        // equality to a delegate pointing to an anoymous lambda method. If the
        // two are equal, it sets the EventHandler to this new delegate and 
        // returns true; otherwise it returns false.

        // This prints 'True', as handler1 is not equal to the delegate
        // declared within the SetAnonymousHandler method.
        Console.WriteLine(SetAnonymousHandler(ref handler1));

        // HOWEVER, now it prints 'False' for a simple reason: the delegate 
        // declared in SetAnonymousHandler points to an actual method. The fact
        // that it is an anonymous method simply means that the compiler
        // automatically generates a "proper" method for it in IL (to see what
        // I mean, read the comment at the bottom of this class). So now,
        // as with handler2 and handler3 above, handler1 and the delegate
        // declared in SetAnonymousHandler point to the same method and are
        // therefore equal; the method returns false.
        Console.WriteLine(SetAnonymousHandler(ref handler1));

        Console.ReadLine();
    }

    static void FirstHandler(object sender, EventArgs e)
    {
        Console.WriteLine("Testing");
    }

    static void SecondHandler(object sender, EventArgs e)
    {
        Console.WriteLine("Testing");
    }

    static bool SetAnonymousHandler(ref EventHandler handler)
    {
        EventHandler anonymous = (sender, e) => Console.WriteLine("Testing");

        if (!handler.Equals(anonymous))
        {
            handler = anonymous;
            return true;
        }
        else
        {
            return false;
        }
    }

    // Note: When the above method is compiled, the C# compiler generates code
    // that would look something like this if translated back from IL to C#
    // (not exactly, but the point is just to illustrate that an anoymous
    // method, after compilation, is really just like a "proper"
    // -- i.e., non-anonymous -- method).

    //static bool SetAnonymousHandler(ref EventHandler handler)
    //{
    //    EventHandler anonymous = SetAnonymousHandler_Anonymous;

    //    if (handler.Equals(anonymous))
    //    {
    //        handler = anonymous;
    //        return true;
    //    }
    //    else
    //    {
    //        return false;
    //    }
    //}

    //static void SetAnonymousHandler_Anonymous(object sender, EventArgs e)
    //{
    //    Console.WriteLine("Testing");
    //}
}
+10

All Articles