.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
Examining the entire method call: TrackAboutControl.
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.