Reflection.Emit实现接口并创建数组IL

时间:2015-11-08 20:36:56

标签: c# proxy runtime il emit

我试图从界面创建一个代理类。在方法中,我只想收集对象数组中的所有参数并传递给已知方法。因此,我设法让它在没有参数和返回类型的情况下工作。一旦我尝试创建我的数组,我得到"附加信息:公共语言运行时检测到一个无效的程序。" ..不知道如何从这里调试,IL代码似乎是正确的(? )。

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());
    }

}

我尝试发射的方法应该是这样的。

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

我在这里缺少什么?

1 个答案:

答案 0 :(得分:4)

您应该初始化本地人:

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[]));

    ....
    ....