Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing interface at run-time: get_Value method not implemented

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.

like image 365
L.E.O Avatar asked Mar 11 '11 19:03

L.E.O


2 Answers

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.

like image 158
Marc Gravell Avatar answered Oct 20 '22 03:10

Marc Gravell


Changing your line to:

MethodAttributes getSetAttr = MethodAttributes.Public | 
    MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Virtual;

Your code then worked for me. (The virtual was required.)

like image 12
Kirk Woll Avatar answered Oct 20 '22 03:10

Kirk Woll