It's fun to talk to people about .NET and make bold, titilating statements like ".NET is type safe". We hear it all the time. While oversimplified a bit, it's basically a valid statement. The C# compiler is also generally wonderful at taking lazily written code and making it function as we intend.
Those things said, it's always best to channel your inner Fox Mulder and "trust
no one". Every once in a while the framework slaps me with some generated native code
which reminds me that I can trust no one. It happened again last night.
In WPF, you can define a special property called a DependencyProperty,
which essentially plumbs your property for WPF's internals, making it play
well with data binding, animation and the like. I had one such definition in my code:
public static readonly DependencyProperty BarValueProperty =
DependencyProperty.RegisterAttached("BarValue",
typeof(UInt32), typeof(SpiderControlWindow), new
UIPropertyMetadata(30));
However, the class in which this definition existed would crash and burn
during instantiation (the good ol’ “object could not be instantiated” error). Managed
debugging was not helpful, so I had to go that extra step and do some (insert gasp here) native
assembly debugging.
Upon stepping through this call in the generated assembly code, I
discovered the issue -- The code calling into the constructor for
UIPropertyMetadata was creating "30" as an immediate value on the
stack, then calling the constructor. The constructor, however, would then store
a pointer to that initialization value for later use, presumably because it
assumed it was being passed a class instance, not an immediate. Well, that's
not so helpful, as that location on the stack was blown away when the
constructor returned, and life continued. Later, the code attempted to use that
pointer, which then happened to be pointing to a null value, and a null
reference exception occurred at the native level, which bubbled up into the very generic and non-helpful .NET exception.
This is an example of where explicit .NET "boxing" is necessary – the constructor's code wants
a .NET class, but doesn't actually specify an strong object type in its definition, so the system doesn't automatically box our parameter. We need to box the parameter on its behalf:
UIPropertyMetadata((UInt32)30)
There we go… that simple “static” cast causes the .NET engine to actually
create a concrete object, and we no longer get a crash and burn. The JIT compiler
generated assembly code now uses a pointer to an object that lives in .NET’s world,
not some volatile set of bits on the stack. No crash and/or burn.
(Though it's interesting to note that if my DependencyProperty is a double, and I pass simply "0.0" into the UIPropertyMetadata constructor, it works fine -- the compiler does the boxing for us... I guess we can't always expect the compiler to intuitively guess what we want.)
And all was right with the world.
Posted
Oct 09 2008, 07:38 AM
by
mike-henderson