可以从动态构造的程序集中调用驻留在“Normal”程序集上的方法吗?
例如,程序集B是从程序集A动态构造的(通过Emit),程序集B需要调用在程序集A上定义的静态方法。
public interface IMapper
{
void Map();
}
public void CreateDynamic() {
AppDomain app = AppDomain.CurrentDomain;
AssemblyName name = new AssemblyName("assemblyB");
AssemblyBuilder assembly = app
.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
ModuleBuilder module = assembly
.DefineDynamicModule(assembly.GetName().Name, "b.dll");
TypeBuilder type = module.DefineType("MyType",
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AutoLayout, null, new[] {typeof (IMapper)});
MethodBuilder method = type
.DefineMethod("Map",
MethodAttributes.Public |
MethodAttributes.HideBySig |
MethodAttributes.Virtual);
ILGenerator il = method.GetILGenerator();
Func<int, TimeSpan> func = i => TimeSpan.FromSeconds(i);
il.Emit(OpCodes.Ldc_I4_S, 10);
il.Emit(OpCodes.Callvirt, func.Method);
il.Emit(OpCodes.Ret);
Type t = type.CreateType();
IMapper mapper = (IMapper) Activator.CreateInstance(t);
mapper.Map();
}
执行Map方法时会抛出MissingMethodExcetion,我现在不知道原因。
答案 0 :(得分:1)
下面的行导致在编译时在类中创建private static
方法。
Func<int, TimeSpan> func = i => TimeSpan.FromSeconds(i);
所以你要做的就是这样。
public class TestClass {
private static TimeSpan CompilerGeneratedMethod(int i) {
return TimeSpan.FromSeconds(i);
}
public void CreateDynamic() {
// Other codes...
var methodInfo = typeof(TestClass).GetMethod("CompilerGeneratedMethod", BindingFlags.Static | BindingFlags.NonPublic);
il.Emit(OpCodes.Ldc_I4_S, 10);
il.Emit(OpCodes.Callvirt, methodInfo);
il.Emit(OpCodes.Ret);
// Other codes...
}
}
现在我们刚刚在AssemblyB中创建了一个试图在另一个程序集中调用private static
方法的类。如果它直接用C#编写,它可能看起来像这样。
public class MyType : IMapper {
public void Map() {
TestClass.CompilerGeneratedMethod(10);
}
}
由于CompilerGeneratedMethod
为private
,因此无法访问。因此,不要使用lamda,而是尝试使用真正声明的public
方法。
public class TestClass {
public static TimeSpan HandWrittenMethod(int i) {
return TimeSpan.FromSeconds(i);
}
public void CreateDynamic() {
// Other codes...
var methodInfo = typeof(TestClass).GetMethod("HandWrittenMethod");
il.Emit(OpCodes.Ldc_I4_S, 10);
il.Emit(OpCodes.Callvirt, methodInfo);
il.Emit(OpCodes.Ret);
// Other codes...
}
}
现在我们有一个小问题。我们尝试使用Callvirt
调用静态方法,该方法应该用于后期绑定方法。我们应该只使用Callvirt
而不是Call
。
il.Emit(OpCodes.Call, methodInfo);