Other Posts in Reflection

  1. Using Reflection to get Assembly Information in C#
  2. Overridding a Property With Reflection.Emit
  3. Shallow Copy of an Object Using Reflection
  4. Dynamically Parsing a String to Any Type When You Don't Know The Type
  5. Reflection.Emit the Simple Way

Overridding a Property With Reflection.Emit

4/29/2009

This isn't a big discussion on Reflection.Emit or a how to when it comes to defining a property. To be honest, you can look that up rather easily. My issue was the fact that I could not for the life of me figure out how to override a virtual property within a base class. For example, let's assume I have this class:

   1: public class ExampleBaseClass
   2: {
   3:       public ExampleBaseClass()
   4:       {
   5:       } 
   6:  
   7:       public virtual string Value { get; set; } 
   8:  
   9: }

and all we want to do is dynamically create a class that takes that as a base class and overrides Value. You'd think that would be easy (and actually it is), but no one ever shows you how... Because normally you'd do something like this:

   1: FieldBuilder ValueField = TypeBuilder.DefineField("_Value", typeof(string), FieldAttributes.Private);
   2:  
   3: PropertyBuilder Property = TypeBuilder.DefineProperty("Value", PropertyAttributes.None, typeof(string), null);
   4:  
   5: MethodAttributes GetSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
   6:  
   7: MethodBuilder ValuePropertyGet = TypeBuilder.DefineMethod("get_Value", GetSetAttributes, typeof(string), Type.EmptyTypes);
   8: ILGenerator Generator = ValuePropertyGet.GetILGenerator();
   9: Generator.Emit(OpCodes.Ldarg_0);
  10: Generator.Emit(OpCodes.Ldfld, ValueField);
  11: Generator.Emit(OpCodes.Ret);
  12:  
  13:  
  14: MethodBuilder ValuePropertySet = TypeBuilder.DefineMethod("set_Value", GetSetAttributes, null, new Type[] { typeof(string) });
  15:  
  16: Generator = ValuePropertySet.GetILGenerator();
  17:  
  18: Generator.Emit(OpCodes.Ldarg_0);
  19: Generator.Emit(OpCodes.Ldarg_1);
  20: Generator.Emit(OpCodes.Stfld, ValueField);
  21: Generator.Emit(OpCodes.Ret);
  22:  
  23: Property.SetGetMethod(ValuePropertyGet);
  24: Property.SetSetMethod(ValuePropertySet);

With TypeBuilder being the TypeBuilder for the class... This seems perfectly logical with the exception that when you try to call Value, the CLR complains that it's ambiguous... After bashing my head against a wall for a while I figured out that there were two Value properties that were defined for the object. One being the virtual, one being this new one that I created. The key to fixing this is to not define the property but only the get and set functions. As such our code above would look like this:

   1: FieldBuilder ValueField = TypeBuilder.DefineField("_Value", typeof(string), FieldAttributes.Private);
   2:  
   3: MethodAttributes GetSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
   4:  
   5: MethodBuilder ValuePropertyGet = TypeBuilder.DefineMethod("get_Value", GetSetAttributes, typeof(string), Type.EmptyTypes);
   6: ILGenerator Generator = ValuePropertyGet.GetILGenerator();
   7: Generator.Emit(OpCodes.Ldarg_0);
   8: Generator.Emit(OpCodes.Ldfld, ValueField);
   9: Generator.Emit(OpCodes.Ret);
  10:  
  11:  
  12: MethodBuilder ValuePropertySet = TypeBuilder.DefineMethod("set_Value", GetSetAttributes, null, new Type[] { typeof(string) });
  13:  
  14: Generator = ValuePropertySet.GetILGenerator();
  15:  
  16: Generator.Emit(OpCodes.Ldarg_0);
  17: Generator.Emit(OpCodes.Ldarg_1);
  18: Generator.Emit(OpCodes.Stfld, ValueField);
  19: Generator.Emit(OpCodes.Ret);

And sadly it took me searching through about 30 blog posts to find one that led me to this fix. Here's hoping this will help you before you reach the fourth page on Google. So try it out, leave feedback, and happy coding.



Comments

SM
November 21, 2011 11:00 AM
Thanks a lot, this probably saved me some time beforehand, when starting to write code for overriding properties! :)