.NET Stack Traces And Anonymous Methods


I learned a little more about stack traces in .NET today… in a very painful manner… but, lesson learned! Hopefully someone else will be able to learn this lesson without having to spend 4 hours on it like I did. Take a look at this stack trace that I was getting in my Compact Framework app, today:

   1: System.NullReferenceException

   2:       Message="NullReferenceException"

   3:       StackTrace:

   4:            at TrackAbout.Mobile.UI.CustomControls.TABaseUserControl.<EndInit>b__8(Object o, EventArgs e)

   5:            at System.ComponentModel.Component.Dispose(Boolean disposing)

   6:            at System.Windows.Forms.Control.Dispose(Boolean disposing)

   7:            at TrackAbout.Mobile.UI.Views.BaseForms.TAForm.Dispose(Boolean disposing)

   8:            at TrackAbout.Mobile.UI.Views.GeneralActions.SetExpirationDateView.Dispose(Boolean disposing)

   9:            at System.ComponentModel.Component.Dispose()

  10:            etc.

  11:            etc.

  12:            ...

</div> </div>

In this stack trace, on line 4, is one very important detail: an anonymous method signature and the parent method that defines it. After several hours of debugging and finally turning on the “catch all” feature for CLR exceptions in Visual Studio, I discovered that line 4 actually translates to this code:

   1: public virtual void EndInit()

   2: {

   3:     ParentForm = FormUtils.GetParentFormOf(this) as TAForm;

   4:     if (ParentForm == null) return;

   5:  

   6:     ParentForm.Closing += FormClose;

   7:     ParentForm.Activated += (o, e) => ParentActivatedHandler(o, e);

   8:     ParentForm.Deactivate += (o, e) => ParentDeactivateHandler(o, e);

   9:     ParentForm.Disposed += (o, e) => ParentDisposedHandler(o, e); 

  10:  

  11:     if (ControlEndInit != null)

  12:     {

  13:         ControlEndInit(this, EventArgs.Empty);

  14:     }

  15: }

</div> </div>

Let me translate this line stack trace into this method… the namespace in the stacktrace is obvious… so is the username. The first part to note is the </strong>. Apparently this means that the EndInit method contains the code that is throwing the exception, but is not actually firing the code that is causing the exception. The next part is where we find what is throwing the exception. Apparently b__8(Object o, EventArgs e) tells me that the failing code in question is an anonymous method. The CLR naming of this method seems cryptic, but also seems like it might be something useful… </p>

Examining the entire method call: TrackAboutControl.b__8(Object o, EventArgs e) w</strong>hat I understand this to be saying is “The EndInit method is defining an anonymous method with a standard event signature at line 8 of the method.” Now I’m not entire sure that “line 8 of the method” is what this anonymous method name means… but it fits in this case… it matches up to the line that was causing the problem. </p>

The problem in this specific case was that this line had a null reference: ParentForm.Disposed += (o, e) => ParentDisposedHandler(o, e);

The ParentDisposedHandler is defined as an event earlier in the class, and since it had no subscribers, it was null. That was easy to fix… just add a null ref check or define the event with a default value of “= delegate{ }”.

So… 4 hours into debugging this issue, it turned out to be 1 line of anonymous method calls. The stack trace was cryptic and confusing to me at first. I hope to retain this lesson and hope to be able to pass this on to someone else that sees a cryptic stack trace such as this, and same someone the same heartache and headache that I went through today.

A Response Concerning Semantics And Intention Revealing Code