Search code examples
c#interfacereflection.emit

How to get an instance of a Reflection.Emit type?


So I have a class:

public class MyClass : IMyClass
{
    public string foo {get;}
    public MyClass bar {get;}
}

And an interface:

public interface IMyClass
{
    string foo {get;}
}

And a system to create an emitted type:

    private static Type MakeDynamicType<T>() where T : class
    {
        var myType = GetTypeBuilder();

        myType.AddInterfaceImplementation(typeof(T));

        var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        foreach (var property in properties)
            AddProperty(myType, property, typeof(T));

        AddCtor(myType, typeof(T));

        return myType.CreateType();
    }

    private static void AddCtor(TypeBuilder myType, Type inputParamType)
    {
        var myCtor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
        var ilGenerator = myCtor.GetILGenerator();
        ilGenerator.Emit(OpCodes.Ret);
    }


    private const MethodAttributes GET_SET_ATTR = MethodAttributes.Public | MethodAttributes.SpecialName |
                                                  MethodAttributes.HideBySig | MethodAttributes.Virtual;

    private static void AddProperty(TypeBuilder myType, PropertyInfo property, Type interfaceType)
    {
        var myField = myType.DefineField($"m_{property.Name}", property.PropertyType, FieldAttributes.Private);

        var myProperty = myType.DefineProperty(property.Name, PropertyAttributes.HasDefault, property.PropertyType,
            parameterTypes: null);

        var interfaceGetMethod = interfaceType.GetMethod($"get_{property.Name}");
        if (interfaceGetMethod != null)
            AddGetter(myType, property, myField, myProperty, interfaceGetMethod);

        var interfaceSetMethod = interfaceType.GetMethod($"set_{property.Name}");
        if (interfaceSetMethod != null)
            AddSetter(myType, property, myField, myProperty, interfaceSetMethod);
    }

    private static void AddGetter(TypeBuilder myType, PropertyInfo property, FieldInfo myField,
        PropertyBuilder myProperty, MethodInfo interfaceGetMethod)
    {
        var myGet = myType.DefineMethod($"get_{property.Name}", GET_SET_ATTR, property.PropertyType,
            Type.EmptyTypes);
        var getIl = myGet.GetILGenerator();
        getIl.Emit(OpCodes.Ldarg_0);
        getIl.Emit(OpCodes.Ldfld, myField);
        getIl.Emit(OpCodes.Ret);
        myProperty.SetGetMethod(myGet);
        myType.DefineMethodOverride(myGet, interfaceGetMethod);
    }

    private static void AddSetter(TypeBuilder myType, PropertyInfo property, FieldInfo myField,
        PropertyBuilder myProperty, MethodInfo interfaceSetMethod)
    {
        var mySet = myType.DefineMethod($"set_{property.Name}", GET_SET_ATTR, returnType: null,
            new[] { property.PropertyType });
        var setIl = mySet.GetILGenerator();
        setIl.Emit(OpCodes.Ldarg_0);
        setIl.Emit(OpCodes.Ldarg_1);
        setIl.Emit(OpCodes.Stfld, myField);
        setIl.Emit(OpCodes.Ret);
        myProperty.SetSetMethod(mySet);
        myType.DefineMethodOverride(mySet, interfaceSetMethod);
    }

    private static TypeBuilder GetTypeBuilder()
    {
        var myDomain = Thread.GetDomain();
        var myAsmName = new AssemblyName("MyDynamicAssembly");

        var myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave);
        var myModBuilder = myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll");

        return myModBuilder.DefineType("MyDynamicType", TypeAttributes.Public);
    }

So now how do I create an instance of my reflected type from an IMyClass type reference to a MyClass object?

    public static IEnumerable<T> ToInterfacedObjects<T>(this IEnumerable<T> data) where T : class
    {
        var myType = MakeDynamicType<T>();

        var list = new List<T>();
        foreach (var datum in data)
        {
            list.Add((T)myType.GetValue(datum));//What do I write for GetValue??
        }

        return list;
    }

My goal is to start with an IMyClass which has an underlying type of MyClass, which has both foo and bar, and end with an IMyClass which has an underlying type of an emitted type, which has foo but not bar.


Solution

  • If you've got an implementation for MakeDynamicType<T>, and assuming your interface has only simple {get; set;} properties, wouldn't this be as simple as:

    public static IList<T> ToInterfacedObjects<T>(this IEnumerable<T> data) where T : class
    {
        var myType = MakeDynamicType<T>();
        var list = new List<T>();
        foreach (var datum in data)
        {
            var obj = (T)Activator.CreateInstance(myType);
            foreach (var pi in typeof(T).GetProperties())
            {
                var val = pi.GetValue(datum);
                pi.SetValue(obj, val);
            }
            list.Add(obj);
        }
        return list;
    }