I was trying to define a type at run-time that inherits from a known class and implements an interface.
public class ParentClass
{
}
public interface IImplementMe
{
double Value{get;set}
}
Here's the code snippet that shows how I try to achieve my goal.
public class ClassBuilder
{
public Type Build()
{
try
{
AssemblyName assemblyName = new AssemblyName("DataBuilderAssembly");
AssemblyBuilder assemBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemBuilder.DefineDynamicModule("DataBuilderModule");
TypeBuilder typeBuilder = moduleBuilder.DefineType("NewClass", TypeAttributes.Class, typeof(ParentClass));
typeBuilder.AddInterfaceImplementation(typeof(IImplementMe));
BuildProperty(typeBuilder, "Value", typeof(double));
Type type = typeBuilder.CreateType();
return type;
}
catch (Exception e)
{
return null;
}
}
private void BuildProperty(TypeBuilder typeBuilder, string name, Type type)
{
FieldBuilder field = typeBuilder.DefineField("m" + name, type, FieldAttributes.Private);
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(name, PropertyAttributes.None, type, null);
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig;
MethodBuilder getter = typeBuilder.DefineMethod("get_" + name, getSetAttr, type, Type.EmptyTypes);
ILGenerator getIL = getter.GetILGenerator();
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, field);
getIL.Emit(OpCodes.Ret);
MethodBuilder setter = typeBuilder.DefineMethod("set_" + name, getSetAttr, null, new Type[] { type });
ILGenerator setIL = setter.GetILGenerator();
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Stfld, field);
setIL.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getter);
propertyBuilder.SetSetMethod(setter);
}
}
For some reason I get an "get_Value method not implemented" exception on calling typeBuilder.CreateType()
. So far unable to see the reason behind it.
The c# implicit interface implementation (by name match) is convenience only; when doing it by hand you need to associate each in the virtual-method table using typeBuilder.DefineMethodOverride, passing in the new (generated) method and the interface method to satisfy. This must done for each method of every interface you want to implement.
Changing your line to:
MethodAttributes getSetAttr = MethodAttributes.Public |
MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;
Your code then worked for me. (The virtual was required.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With