I've been experimenting with the idea of using System.Reflection.Emit to generate code from interfaces. If you're not familiar with this namespace, it contains classes to generate compiled assemblies programmatically. Regex uses this when compiling a regular expression for faster execution. Instead of parsing the expression each time, it generates on-the-fly a class that can be used to execute the expression. This namespace is also used by Mock Type frameworks such as RhinoMocks and TypeMock. Given a base class or interface, these generate on-the-fly a class that can mimic the base enough to use when unit testing. I'm sure there are other places this is used, but suffice it to say this is one of those obscure corners of the framework that us Morts rarely dig into. So it's not surprising that I would run into an obscure error that stumped even Google.
I religiously studied the MSDN examples and wrote code to let me do something like this:
ICustomer concreteType = CodeGenerator<ICustomer>.GetInstance();
You can see how freaking awesome this could be for component development- I get, at runtime, a class that implements my interface, but I don't have to wire up goo like INotifyPropertyChanged, IDataError, property getter/setters, etc. Depending on how my tinkering goes, more on the awesomeness later. The error I was getting whenever I called typeBuilder.CreateType() was:
System.TypeLoadException: Method 'get_Id' in type 'Customer' from assembly 'TypeAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation
Except I WAS implementing 'get_Id'. I copied the code to do it straight from MSDN! See:
MethodAttributes getSetAttributes = MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig;
var getMethodBuilder = typeBuilder.DefineMethod("get_" + propertyOnInterface.Name,
getSetAttributes,
propertyOnInterface.PropertyType,
Type.EmptyTypes);
ILGenerator getMethodIl = getMethodBuilder.GetILGenerator();
getMethodIl.Emit(OpCodes.Ldarg_0);
getMethodIl.Emit(OpCodes.Ldfld, fieldBuilder);
getMethodIl.Emit(OpCodes.Ret);
propBuilder.SetGetMethod(getMethodBuilder);
Much googling turned up only a few unrelated posts. After testing, I discovered that removing a call to 'AddInterfaceImplementation' fixed the issue- though the resulting class no longer implemented my interface. Clearly the interface was generating some sort of code. Some more digging, and I figured out the solution:
MethodAttributes getSetAttributes = MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig;| MethodAttributes.Virtual;
I could be flawed in my understanding here, but apparently, when adding an interface, .NET treats property get and set accessors sort of like abstract methods. The code I was generating did implement 'get_Id', but did not mark it as overriding the interface's definition. So, when creating the type, there was the interfaces' unfinished implementation of 'get_Id', and my completely unrelated 'get_Id'.
So anyway, hopefully this post will make it into Google and help some other poor guy who, late one night, finds themselves turning over parts of the framework better left alone.