如何在反射发出类中发出本地人init[0]字符串V_0?

问题描述

在这一行抛出异常:

s = method.Invoke(student,new object[] { "pig" });

这是完整的代码,您可以创建一个新的.net framewrok控制台应用程序并运行它

public class Program
    {
        static void Main(string[] args)
        {
            MethodInfo method = typeof(Student).getmethod("SayHello");

            var student1 = new Student("lucy");
            object s = method.Invoke(student1,new object[] { "pig" });

            var student = BuildType(typeof(Person));
            //todo:throw an exception here ??
            s = method.Invoke(student,new object[] { "pig" });

            Console.ReadKey();
        }

        public static object BuildType(Type baseType)
        {
            AppDomain dom = AppDomain.CurrentDomain;
            AssemblyName asmName = new AssemblyName("DynamicAssembly");
            AssemblyBuilder assemblyBuilder = dom.DefineDynamicAssembly(asmName,AssemblyBuilderAccess.RunAndSave);

            //AssemblyName DemoName = new AssemblyName("DynamicAssembly");
            //AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(DemoName,AssemblyBuilderAccess.RunAndSave);

            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("LjxModule","LjxModule.dll");
            //dynamicly create Class
            TypeBuilder tb = moduleBuilder.DefineType("MyStudent",TypeAttributes.Public,baseType);
            Type[] ctorPaTypes = new Type[] { typeof(string) };

            ConstructorBuilder ctorBuilder = tb.DefineConstructor(MethodAttributes.Public,CallingConventions.Standard | CallingConventions.HasThis,ctorPaTypes);
            ILGenerator msilGenerator = ctorBuilder.GetILGenerator();
            msilGenerator.Emit(OpCodes.Ldarg_0);//push this
            msilGenerator.Emit(OpCodes.Ldarg_1);
            ConstructorInfo baseCtor = baseType.GetConstructor(ctorPaTypes);
            if (baseCtor == null)
            {
                throw new Exception("some exception!");
            }
            msilGenerator.Emit(OpCodes.Call,baseCtor);
            msilGenerator.Emit(OpCodes.nop);
            msilGenerator.Emit(OpCodes.nop);
            msilGenerator.Emit(OpCodes.Ret);

            //override method
            MethodBuilder executeAsyncmethod = tb.DefineMethod("SayHello",MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,typeof(string),new Type[] { typeof(object) });
            MethodInfo baseMethodInfo = baseType.getmethod("SayHello",new Type[] { typeof(object) });
            if (baseMethodInfo == null)
            {
                throw new Exception("some exception!");
            }
            ILGenerator ilGen = executeAsyncmethod.GetILGenerator();
            var mylabel = ilGen.DefineLabel();

            //todo:this line code emit:      .locals init (string[] V_0)
            //but i found Student class' il is:     .locals init ([0] string V_0)
            var v1 = ilGen.DeclareLocal(typeof(string));

            ilGen.Emit(OpCodes.nop);
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldarg_1);
            ilGen.Emit(OpCodes.Call,baseMethodInfo);
            ilGen.Emit(OpCodes.Stloc_0);
            ilGen.Emit(OpCodes.Br_S,mylabel);
            ilGen.MarkLabel(mylabel);
            ilGen.Emit(OpCodes.Ldloc_0);
            ilGen.Emit(OpCodes.Ret);

            if (baseMethodInfo == null)
            {
                throw new Exception("some exception!");
            }
            
            //tb.DefineMethodoverride(executeAsyncmethod,baseMethodInfo);

            Type resultType = tb.CreateType();

            //save dll
            assemblyBuilder.Save("LjxModule.dll");

            //create instance
            var arg0 = "jacks";
            if (resultType == null)
            {
                throw new Exception("some exception!");
            }
            return Activator.CreateInstance(resultType,arg0);
        }

        public static Type SingleTypeByQualifiedname(string assemblyQualifiedname)
        {
            Type paramType = Type.GetType(assemblyQualifiedname);
            if (paramType == null)
            {
                throw new Exception($"not found {assemblyQualifiedname}!");
            }
            return paramType;
        }
    }

    public class Person
    {
        public Person(string name)
        {
            Name = name;
        }
        public string Name { get; set; }

        public virtual string SayHello(object obj)
        {
            return Name + "say:" + obj.ToString();
        }
    }

    public class Student : Person
    {
        public Student(string name) : base(name)
        {
        }

        public override string SayHello(object obj)
        {
            return base.SayHello(obj);
        }
    }

这是发出的 IL:

.method public hidebysig virtual instance string SayHello(object A_1) cil managed
{
  // 代码大小       13 (0xd)
  .maxstack  3
  .locals init (string[] V_0)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  call       instance string [DotFxConsoleApp1]DotFxConsoleApp1.Model.Person::SayHello(object)
  IL_0008:  stloc.0
  IL_0009:  br.s       IL_000b
  IL_000b:  ldloc.0
  IL_000c:  ret
} // end of method MyStudent::SayHello

这是学生类的IL

.method public hidebysig virtual instance string SayHello(object obj) cil managed
{
  // 代码大小       13 (0xd)
  .maxstack  2
  .locals init ([0] string V_0)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  call       instance string DotFxConsoleApp1.Model.Person::SayHello(object)
  IL_0008:  stloc.0
  IL_0009:  br.s       IL_000b
  IL_000b:  ldloc.0
  IL_000c:  ret
} // end of method Student::SayHello

似乎唯一的区别是 .locals init (string[] V_0),我该如何修复它?有人可以帮我吗?非常感谢!

解决方法

我已经知道原因了。我犯了一个错误。我已经使用 Student.SayHello MethodInfo 来调用 MyStudent 实例。我已经更正了代码,现在运行良好。

MethodInfo method = typeof(Student).GetMethod("SayHello");

            var student1 = new Student("lucy");
            object s = method.Invoke(student1,new object[] { "pig" });

            var myStuType = BuildType(typeof(Person));
            MethodInfo dyMethod = myStuType.GetMethod("SayHello");
            var student = Activator.CreateInstance(myStuType,new string[] { "jack" });
            s = dyMethod.Invoke(student,new object[] { "pig" });