簡體   English   中英

用Reflection.Emit調用AutoGenerated類的方法

[英]Invoking method of AutoGenerated class with Reflection.Emit

你好,我想知道如何在不使用reflexion的情況下調用尚未存在的類的方法。如你所見,我正在使用生成器類Weaver (使用Reflection.Emit )並返回Func<object> (我無法指定動態類型)。檢索實例時,如何調用其方法之一,特別是DoInt

我想自動生成

class Gen {
            public Gen() {

            }
            public int DoInt(int a,string b) {
               int rez=a+b.count();
                return 3;
            }
        }

發電機類

class Weaver {

            public static Func<object> Weave() {
                var weaver = new Weaver();
                weaver.Run();
                return weaver.output as Func<object>;

            }


            private AssemblyBuilder assemblyBuilder;
            private ModuleBuilder moduleBuilder;
            private TypeBuilder typebuilder;

            private object output;
            public Weaver() {

            }


            private void Run() {
                this.DefineAssembly();
                this.DefineModule();
                this.DefineClass();
                this.DefineMethod();
                this.Wrap();
            }


            private void DefineAssembly() {
                AssemblyName name = new AssemblyName("Coda");
                AppDomain domain = AppDomain.CurrentDomain;
                assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndCollect);
            }

            private void DefineModule() {
                this.moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyBuilder.FullName + ".dll");
            }
            private void DefineClass() {
                this.typebuilder = this.moduleBuilder.DefineType("A", 
                    TypeAttributes.Abstract|TypeAttributes.Public|TypeAttributes.BeforeFieldInit|TypeAttributes.AnsiClass|TypeAttributes.AutoClass,
                    typeof(object), null );
            }
            private void DefineMethod() {
                MethodBuilder methodBuilder = this.typebuilder.DefineMethod("DoInt", MethodAttributes.Public, typeof(int), new[] { typeof(int), typeof(string) });
                var il = methodBuilder.GetILGenerator();
                il.Emit(OpCodes.Ldarg_1);
                il.EmitCall(OpCodes.Call, typeof(Enumerable).GetMethod("Count", BindingFlags.Static), null);
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Add);
                il.Emit(OpCodes.Ret);
            }

            private void Wrap() {
                Type type = typebuilder.CreateType();
                this.output = Activator.CreateInstance(type);
            }

        }

主要

static void Main(string[] args)
        {
            string t = "astada";
            var c = Weaver.Weave();
            var result=c.GetType().GetMethod("DoInt").Invoke(null, new object[] { 3, "mystring" });  //should be 3+ "mystring".Count() 
            Console.ReadLine();
        }

要使其正常運行,首先需要修復Weaver ,因為它包含幾個錯誤:

private void DefineClass()
{
    // TypeAttributes.Abstract should not be used here as we want to create
    // type that can be instantiated
    this.typebuilder = this.moduleBuilder.DefineType(
        "A",
        TypeAttributes.Public | TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass,
        typeof(object),
        null);
}

private void DefineMethod()
{
    MethodBuilder methodBuilder = this.typebuilder.DefineMethod(
        "DoInt",
        MethodAttributes.Public,
        typeof(int), new[] { typeof(int), typeof(string) });

    var il = methodBuilder.GetILGenerator();

    // Arguments are counted from zero. For instance methods, argument0 is
    // reserved for 'this' instance. So to get "string" argument (second "real" argument),
    // you need Ldarg_2
    il.Emit(OpCodes.Ldarg_2);

    // You cannot get MethodInfo for "Count" method with simple GetMethod(),
    // since it is generic method with several overloads.
    var countMethodInfo = typeof(Enumerable)
        .GetMethods(BindingFlags.Public | BindingFlags.Static)
        .Where(m => m.Name == "Count")
        .Where(m => m.GetParameters().Length == 1)
        .Single()
        //We want Count<char>() method, because we want to count characters on string (casted to IEnumerable<char>).
        .MakeGenericMethod(typeof(char));
    il.EmitCall(OpCodes.Call, countMethodInfo, null);
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Add);
    il.Emit(OpCodes.Ret);
}

public static object Weave()
{
    var weaver = new Weaver();
    weaver.Run();
    // return weaver.output as Func<object>;
    // Output is an instance of an (dynamically generated) 'A' class, not a Func<>
    return weaver.output;
}

現在有幾種方法可以調用A.DoInt:

  1. 反射

     var c = Weaver.Weave(); var result = (int)c.GetType().GetMethod("DoInt").Invoke(c, new Object[] { 3, "foo" }); 
  2. 創建委托

     var c = Weaver.Weave(); var mi = c.GetType().GetMethod("DoInt"); var del = (Func<int, string, int>)Delegate.CreateDelegate(typeof(Func<int, string, int>), c, mi); var result = del(3, "foo"); 
  3. 動態

     var d = Weaver.Weave() as dynamic; var result = (int)d.DoInt(3, "foo"); 
  4. 介面

    這是最難做到的。 首先,您必須聲明接口,例如:

     public interface IDoInt { int DoInt(int i, string s); } 

    您需要在另一個程序集中聲明此接口,否則將無法在動態定義的程序集中使用此類型(由於循環引用)。

    然后,您需要稍微更改Weaver ,以使您的A類型實現此接口:

     private void DefineClass() { this.typebuilder = this.moduleBuilder.DefineType( "A", TypeAttributes.Public | TypeAttributes.BeforeFieldInit | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof(object), new[] { typeof(IDoInt) }); } private void DefineMethod() { MethodBuilder methodBuilder = this.typebuilder.DefineMethod( "DoInt", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, typeof(int), new[] { typeof(int), typeof(string) }); // ... rest ot the method is the same ... // just add this at the end of the method to implement the IDoInt interface this.typebuilder.DefineMethodOverride(methodBuilder, typeof(IDoInt).GetMethod("DoInt")); } 

    現在您可以在IDoInt接口上調用DoInt

     var i = Weaver.Weave() as IDoInt; var result = i.DoInt(3, "foo"); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM