Tuesday, May 29, 2012

Lambda closure and compiler generated code in C#

I came across an interesting problem today.

In our WPF application we are heavily using unity and prism framework and we build pieces of application using unity IModule interfaces. We also make use of EventAggregator.

Now we had a perfectly fine piece of code that was working without any problem so far until today. Here is the code snippet

Note: this is only a sample code to illustrate the problem.

class MyModule:IModule
{
void Initialize(IEventAggregator aggregator)
{
Parameter param = new Parameter();
aggregator.GetEvent<MyEvent>.Subscribe(
() => {SomeStaticMethod(param);});
}

public static void SomeStaticMethod(Parameter param1)
{
//Do Something
}
}


So far so good. Now one of my collegeue made a small change to the code.



class MyModule:IModule
{
ISomeType someTypeObj;
void Initialize(IEventAggregator aggregator, ISomeType someTypeObject)
{
someTypeObj = someTypeObject
Parameter param = new Parameter();
aggregator.GetEvent<MyEvent>.Subscribe(
() => {SomeStaticMethod(param, someTypeObj);});
}

public static void SomeStaticMethod(Parameter param1, ISomeType someTypeObject)
{
//Do Something
}
}


 



I guess you can see the small difference. We just added a new parameter to the method call in our lambda and whoa our application stops working…



Looking at the change doesn’t give a clue. Why the heck it stopped working with a small change.



Here reflector came to our rescue. After fiddling with our debugger and looking at the reflected code we figured out the issue and it was a very interesting find.



Previously we were only calling a single static method in our lambda and passing a local variable, hence compiler optimized the generated code and produced a static method for our lambda. In the second case though we passed an instance variable and hence generated method had to be an instance method.



Now you must be wondering what difference does it make. But it does when you are using it inside IModule and lambda is used by EventAggregator. By definition IModules are short lived and unless there is a reference to the Module object, it will be garbage collected. Secondly, EventAggregator by default keeps a weak reference to the event handler in the aggregated list. So now since my Module is dead so is my event handler. This event handler was doing stuff, which was life line of my application and hence it went dead too.



Learnings:




  • Compiler does and will optimize anything it wants to and it wont ask you.


  • Test your code thoroughly event when you think it’s a small change.


  • Debug, Debug, Debug…….



 

Google Analytics

Popular Posts

Powered by Blogger.