Search code examples
c#proxyruntimeilemit

Reflection.Emit Implement interface and create array IL


Im trying to create a Proxy Class from an interface. In the methods I just want to collect all arguments in an object array and pass on to a known method. So faar I have managed to get it working without params and with return types. As soon as I try to create my array I get "Additional information: Common Language Runtime detected an invalid program.".. Dont really know how to debug from here and the IL codes seems to be correct ( ? ).

public class Program
{
    static void Main(string[] args)
    {
        var v = CreateProxy<IFoo>();
        v.DoSomething();
    }

    public static void TheMethod(object[] args)
    {

    }

    public interface IFoo
    {
        void DoSomething();
    }

    public static T CreateProxy<T>()
    {
        var interfaceType = typeof(T);

        AssemblyName assemblyName = new AssemblyName(string.Format("tmp_{0}", interfaceType.FullName));
        string moduleName = string.Format("{0}.dll", assemblyName.Name);
        string ns = interfaceType.Namespace;
        if (!string.IsNullOrEmpty(ns))
            ns += ".";

        var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,AssemblyBuilderAccess.RunAndSave);
        var module = assembly.DefineDynamicModule(moduleName, false);
        var type = module.DefineType(String.Format("{0}Proxy_{1}", ns, interfaceType.Name), TypeAttributes.Class | TypeAttributes.AnsiClass |TypeAttributes.Sealed |TypeAttributes.NotPublic);
        type.AddInterfaceImplementation(interfaceType);

        //Constructor
        var ctor = type.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] {});
        var generator = ctor.GetILGenerator();
        generator.Emit(OpCodes.Ret);

        //Methods
        foreach (var method in interfaceType.GetMethods())
        {
            var args = method.GetParameters();
            var methodImpl = type.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, (from arg in args select arg.ParameterType).ToArray());
            generator = methodImpl.GetILGenerator();

            generator.Emit(OpCodes.Nop);
            generator.Emit(OpCodes.Ldc_I4_1);
            generator.Emit(OpCodes.Newarr, typeof(object));
            generator.Emit(OpCodes.Stloc_0);
            generator.Emit(OpCodes.Ldloc_0); 
            generator.Emit(OpCodes.Call, typeof(Program).GetMethod(nameof(Program.TheMethod)));
            generator.Emit(OpCodes.Nop);

            generator.Emit(OpCodes.Ret);
        }

        return (T)Activator.CreateInstance(type.CreateType());
    }

}

The method im trying to Emit should look like this.

    public void DoSomething()
    {
        object[] arr = new object[1];
        Program.TheMethod(arr);
    }

What am I missing here ?


Solution

  • You should initialize locals:

    foreach (var method in interfaceType.GetMethods())
    {
        var args = method.GetParameters();
        var methodImpl = type.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, (from arg in args select arg.ParameterType).ToArray());
        generator = methodImpl.GetILGenerator();
    
        generator.DeclareLocal(typeof(object[]));
    
        ....
        ....