Click here to Skip to main content
12,955,001 members (65,803 online)
Click here to Skip to main content
Add your own
alternative version


17 bookmarked
Posted 9 Dec 2012

The lambdas, the anonymous and the events

, 30 Oct 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
The subscribe/unsubscribe behavior.

Combining lambdas, anonymous methods and events feels natural in C#, and we use them almost as a reflex, they help us to create closures and avoid creating state variables outside the scope of our methods or passing extra state data through event calls.

But one thing that come with events is the fact that writing good applications implies making good use of the resources, meaning we have to dispose those we no longer need. When using events with lambdas and anonymous methods, is possible to forget about that, thus writing code that is not efficient and prone to crashes. I will start this 2-part series talking about the subscribe/unsubscribe behavior.

Subscribe/Unsubscribe lambdas and anonymous methods

Let's begin with a basic scenario using events in a single-thread context for now; just to keep it simple. The code fragment below contains the HelloEventArgs implementation as well as the publisher class MyClassWithEvents.

public class HelloEventArgs:EventArgs
    public string Content { get; private set; }

    public HelloEventArgs(string content)
        this.Content = content;

public class MyClassWithEvents
    public event EventHandler<HelloEventArgs> SayHelloCompleted;

    public void OnSayHelloCompleted(HelloEventArgs e)
        var handler = SayHelloCompleted;
        if (handler != null) handler(this, e);

    public void SayHello(string s)
        Console.WriteLine("Hello " + s);
        OnSayHelloCompleted(new HelloEventArgs(s));

I know I can make EventArgs generic as well, but that's not the point of this entry. Now... how do we subscribe to - and use - the event? Well the traditional way is just using a method and the "+=" operator.

   MyClassWithEvents owner = ...; 
   owner.SayHelloCompleted += OwnerSayHelloCompleted;

static void OwnerSayHelloCompleted(object sender, HelloEventArgs e)
    Console.WriteLine("Somebody said hello to " + e.Content);

Of course we can always use an anonymous method or a lambda expression, that we got since C# 3.0, and go like this:

owner.SayHelloCompleted += (sender, e) =>  Console.WriteLine("Somebody said hello to " + e.Content);

Lambdas and anonymous methods help us to code in a cleaner way, especially when it comes to introduce closures, so we don't have to be messing around passing state information. The compiler wraps that up for us. Writing lambdas feels good, it looks good, but it might not always be such a good idea. Why? well, while we can unsubscribe a method from a multicast delegateby solely using he -= operator, we can't do such thing when using anonymous methods and lambdas; even when the compiler will allow you to do something like this:

//notice the -= operator!!, this will compile but not work as expected
owner.SayHelloCompleted -= 
  (sender, e) =>  Console.WriteLine("Somebody said hello to " + e.Content);

You must know that per C# specification, two anonymous methods or lambdas with the same code might not generate the same code, also in fact, it won't reference the same object in memory. The workaround is simple, if you feel the need to use lambdas (maybe because you need closures and a cleaner-looking code) you must store the reference to the expression or delegate.

EventHandler<HelloEventArgs> myHandler = //store a reference
(sender, e) => Console.WriteLine("Somebody said hello to " + e.Content);
owner.SayHelloCompleted += myHandler;
//...then unsubscribe when ready
owner.SayHelloCompleted -= myHandler;

Now everything comes with a price.Writing a event handler that unsubscribes itself is different now.

EventHandler<HelloEventArgs> myHandler = null; //make it null first
 myhandler =  (sender, e) =>  //assign it later (to allow capturing the variable)
 Console.WriteLine("Somebody said hello to " + e.Content);
//...then unsubscribe when ready from inside the handler
 owner.SayHelloCompleted -= myHandler;
 owner.SayHelloCompleted += myHandler;
It also moves the problem of the shared state data to a new one: you have to hold a reference to the method and keep it, or do it like the code above, which is the opposite we want if we are already using this model because of the prettiness of closures. And it becomes painful when multithreading is involved.

Microsoft recommendation in this matter is pretty clear, you should avoid using lambdas and anonymous method on events if you need to unsubscribe at a later time. And the word "need" here is the whole key. Just be careful when using lambdas on events. If you don't unsubscribe from an event and keep references to variables outside the scope, the Garbage Collector won't be able to clean up that after you.

A weird tip is to create a "cleanup" method, that assigns null to the event variable from inside the class that holds the event (since the event won't be directly accessible from the outside) and thus, removing all subscribers (no selective procedure here, is all or nothing).

public void CleanupSubscribers()
     SayHelloCompleted = null;

Is not the prettiest thing, but it might be of use in many scenarios and will definitely do the cleanup.Of course is up to you to perform the cleaning, so be careful. Another problem with this extreme approach is that in a multithreading environment is almost useless. Care to see why?

Will see more on that on the next entry!


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Leonardo Paneque
United States United States
Leonardo loves to code with C# on any platform and OS.
He has a Master degree in Computer Sciences and likes to share code and ideas.

You may also be interested in...

Comments and Discussions

QuestionEvent subscriptions don't neccessirly keep the oject alive, do they? Pin
markmnl3-Nov-13 20:08
membermarkmnl3-Nov-13 20:08 
AnswerRe: Event subscriptions don't neccessirly keep the oject alive, do they? Pin
Leonardo Paneque4-Nov-13 5:28
memberLeonardo Paneque4-Nov-13 5:28 
SuggestionAlternate solution.... Pin
Andrew Rissing11-Dec-12 4:45
memberAndrew Rissing11-Dec-12 4:45 
GeneralMy vote of 5 Pin
Sakshi Smriti10-Dec-12 16:19
memberSakshi Smriti10-Dec-12 16:19 
GeneralRe: My vote of 5 Pin
Leonardo Paneque10-Dec-12 17:43
memberLeonardo Paneque10-Dec-12 17:43 
QuestionNice! Pin
Tee12310-Dec-12 15:21
memberTee12310-Dec-12 15:21 
AnswerRe: Nice! Pin
Leonardo Paneque10-Dec-12 17:42
memberLeonardo Paneque10-Dec-12 17:42 
GeneralMy vote of 4 Pin
John Brett9-Dec-12 21:41
memberJohn Brett9-Dec-12 21:41 
GeneralRe: My vote of 4 Pin
Leonardo Paneque10-Dec-12 4:34
memberLeonardo Paneque10-Dec-12 4:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.170525.1 | Last Updated 30 Oct 2013
Article Copyright 2012 by Leonardo Paneque
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid