我正在使用Reflection.Emit-Namespace在运行时设计一个。net - type。目前,我将生成一个方法,该方法调用生成类中已经存在的方法:
Dim AssemblyBuilder As AssemblyBuilder = Nothing
Dim ModuleBuilder As ModuleBuilder = Nothing
Dim TypeBuilder As TypeBuilder = Nothing
Dim MethodBuilder As MethodBuilder
Dim ReturnType As Type = Nothing
AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(New AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.RunAndSave)
ModuleBuilder = AssemblyBuilder.DefineDynamicModule("DynamicAsssembly", "DynamicAssembly.dll")
TypeBuilder = ModuleBuilder.DefineType("DynamicType")
MethodBuilder = TypeBuilder.DefineMethod("Do", MethodAttributes.Public, Nothing, Nothing)
以上工作。
MethodBuilder.GetILGenerator.EmitCall(OpCodes.Call, Me.GetType.GetMethod("DisplayString"), Nothing)
MethodBuilder.GetILGenerator.Emit(OpCodes.Ret)
ReturnType = TypeBuilder.CreateType()
Activator.CreateInstance(ReturnType)
这是我通常想要做的:调用位于执行类本身的方法。但是当调用下面的函数时,会抛出异常。
ReturnType.GetMethod("Do").Invoke(Activator.CreateInstance(ReturnType), Nothing)
内部异常是(类似于):InvalidProgramException, "公共语言运行时发现了一个无效的程序。"
如果我将上面发出调用的行替换为
MethodBuilder.GetILGenerator.Emit(OpCodes.Ldstr, "test")
MethodBuilder.GetILGenerator.EmitCall(OpCodes.Call, GetType(System.Windows.Forms.MessageBox).GetMethod("Show", {GetType(String)}), {GetType(String)})
MethodBuilder.GetILGenerator.Emit(OpCodes.Pop)
它工作得很好。
我假设发生了一个问题,因为执行程序集类型和它们的成员是不可访问的,但这是真的吗?我可以做些什么来让它运行?
感谢莫莫DisplayString
是静态方法(MessageBox.Show
是)吗?
如果没有,则需要一个实例来调用
上的方法。请给我破损的VB,已经有一段时间了;)
dim fieldBuilder as FieldBuilder = typeBuilder.DefineField(
"o", Me.GetType(),
FieldAttributes.InitOnly | FieldAttributes.Private);
dim constructor as ConstructorBuilder = typeBuilder.DefineConstructor(
MethodAttributes.Public |
MethodAttributes.HideBySig |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName,
CallingConventions.Standard, new[] { Me.GetType() });
//Make tho CTOR for the dynamic type, it needs to take an argument of the
//instance to call the method on (in this case it will be Me)
dim il as ILGenerator = constructor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, baseCtor);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Stfld, fieldBuilder);
il.Emit(OpCodes.Ret);
// Make the method
il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg, 0);
il.Emit(OpCodes.Ldfld, fieldBuilder);
il.Emit(OpCodes.Ldstr, 'test');
il.Emit(OpCodes.Callvirt, Me.GetType.GetMethod ...
il.Emit(OpCodes.Ret);
希望对你有帮助。
了解需要发出什么的最好方法之一是像往常一样使用write类,然后在其上使用IL DASM
,然后您可以从中复制OpCodes。