Skip to main content

Curious Case Of Anonymous Delegates !!!

Senthil has left us thrilled in his new post, and also inspired me to write about the topic. Although, anonymous delegates have become a mundane stuff amongst programmers, there is still these subtle stuff left unexplored. Alright, let us try to answer Senthil's question before he unravels the mystery in his next post.

A delegate is identified by its target. The target is the method to be executed on a delegate invocation and its associated instance or type. If the target is an instance method, the delegate preserves the target method pointer and the object instance. If the target is a static method, the delegate preserves the target method pointer and the type to which it belongs. So when a code like the one below to register a method to an event (or multicast delegate) is executed, a delegate object (EventHandler here) with the target information embedded is created and added to the invocation list of the event (or multicast delegate, KeyPressed here).

class SomeForm
{
   private Control control = new Control();

   public void OnFormLoad(object sender, EventArgs args)
   {
      control.KeyPressed += new EventHandler(OnKeyPressed);
   }

   // Rest of the code omitted to be succinct
};

Likewise, when unregistering the method handler, a new (EventHandler) delegate object is created with the same target information as above. As said earlier, a delegate is identified by its target. In other words, the Equals override on the delegate uses the target information for comparing two delegate objects. Hence in the following code that unregisters the method handler, the invocation list is searched for a delegate instance with the specified target information (Method: OnKeyPressed, Instance: SomeForm instance).

In the case of anonymous delegates, the compiler transforms the inline method code into a

  • static method, if the inline method code does not use any of the class's instance members or local variables or if it uses only the static members of the class.
  • instance method, if the inline method code uses at least one class member, any or no static members, and no local variables.
  • class with a method that represents the inline method code, if the inline method code uses local variables no matter whether it uses the class members or not.

Those might not be the extensive set of rules but sure are enough for our discussion. Given the following questionable code,

public EventHandler IfEnabledThenDo(EventHandler actualAction)
{
   return (sender, args) => {
      if (args.Control.Enabled)
      {
         actualAction(sender, args);
      }
   };
}

public void Initialize()
{
   control.KeyPressed += IfEnabledThenDo(control_KeyPressed);
}

public void Destroy()
{
   control.KeyPressed -= IfEnabledThenDo(control_KeyPressed);
}

we realize, without doubt, that the anonymous delegate (returned by IfEnabledThenDo) would be transported into a compiler generated anonymous class. Later when IfEnabledThenDo is called for registering\unregistering the method handler, an instance of anonymous class is created and the (EventHandler) delegate is returned. And here lies the subtlety. Although the delegate from IfEnabledThenDo targets the method inside the anonymous class, the instance preserved as a part of the target information are different during registration and un-registration. In other words, the target method of the delegate returned by IfEnabledThenDo belong to different instances of the anonymous class. Hence the pretty code to unregister the (key pressed) method handler would not be actually unregistering since there would be a delegate previously registered in the invocation list of the (KeyPressed) event with the target instance same as the one used in the unregistration line of code. Very subtle!

Usually the hand written code tends to keep the registration and unregistration of the method handlers in the same class and so belong to the respective instances. Not so when you like watching the compiler magic.

Let us wait and see what Senthil says.

Post a Comment

Popular posts from this blog

Passing CComPtr By Value !!!

This is about a killer bug identified by our chief software engineer in our software. What was devised for ease of use and write smart code ended up in this killer defect due to improper perception. Ok, let us go!CComPtr is a template class in ATL designed to wrap the discrete functionality of COM object management - AddRef and Release. Technically it is a smart pointer for a COM object.void SomeMethod() { CComPtr siPtr; HRESULT hr = siPtr.CoCreateInstance(CLSID_SomeComponent); siPtr->MethodOne(20, L"Hello"); }Without CComPtr, the code wouldn't be as elegant as above. The code would be spilled with AddRef and Release. Besides, writing code to Release after use under any circumstance is either hard or ugly. CComPtr automatically takes care of releasing in its destructor just like std::auto_ptr. As a C++ programmer, we must be able to appreciate the inevitability of the destructor and its immense use in writing smart code. However there is a difference between …

jqGrid: Handling array data !!!

This post is primarily a personal reference. I also consider this a tribute to Oleg, who was fundamental in improving my understanding of the jqGrid internals - the way it handles source data types, which if I may say led him in discovering a bug in jqGrid.

If you are working with local array data as the source for jqGrid, meaning you will get the data from the server but want the jqGrid not to talk to the server anymore, and want to have custom handling of the edit functionality/form and delete functionality, it is not going to be straightforward - you need to have a decent understanding of how jqGrid works, and you should be aware of the bug Oleg pointed in our discussion. I repeat this is all about using jqGrid to manage array data locally, no posting to server when you edit or delete, which is where the bug is.

$('#grid').jqGrid('navGrid', '#pager', { recreateForm: true, add: false, search: false, refresh: false, …

Offering __FILE__ and __LINE__ for C# !!!

THIS POST USES SYNTAXHIGHLIGHTER AND HAS ISSUES RENDERING CODE ONLY IN CHROME
Not the same way but we could say better.
Visual Studio 2012, another power packed release of Visual Studio, among a lot of other powerful fancy language features, offers the ability to deduce the method caller details at compile time.
C++ offered the compiler defined macros __FILE__ and __LINE__ (and __DATE__ and __TIME__), which are primarily intended for diagnostic purposes in a program, whereby the caller information is captured and logged. For instance, using __LINE__ would be replaced with the exact line number in the file where this macro has been used. That sometimes beats the purpose and doesn't gives us what we actually expect. Let's see.

For instance, suppose you wish to write a verbose Log method with an idea to print rich diagnostic details, it would look something like this.
void LogException(const std::string& logText, const std::string& fileName, …