我试图在运行时将以下代码作为IL代码发出。
class TestObject {
public int Hello {get;set;}
public int Test {get;set;}
}
static TestObject test(BinaryReader reader) {
var a = new TestObject();
a.Hello = reader.ReadInt32();
a.Test = reader.ReadInt32();
return a;
}
LINQPad显示:
test:
IL_0000: nop
IL_0001: newobj UserQuery+TestObject..ctor
IL_0006: stloc.0 // a
IL_0007: ldloc.0 // a
IL_0008: ldarg.0
IL_0009: callvirt System.IO.BinaryReader.ReadInt32
IL_000E: callvirt UserQuery+TestObject.set_Hello
IL_0013: nop
IL_0014: ldloc.0 // a
IL_0015: ldarg.0
IL_0016: callvirt System.IO.BinaryReader.ReadInt32
IL_001B: callvirt UserQuery+TestObject.set_Test
IL_0020: nop
IL_0021: ldloc.0 // a
IL_0022: stloc.1
IL_0023: br.s IL_0025
IL_0025: ldloc.1
IL_0026: ret
尝试使用C#重现它:
var method = new DynamicMethod("DynamicCreate", typeof(TestSubject), new Type[] {typeof(BinaryReader)},
typeof(TestSubject).Module);
var il = method.GetILGenerator();
var properties = from property in typeof(TestSubject).GetProperties()
let orderAttribute =
property.GetCustomAttributes(typeof(OrderAttribute), false).SingleOrDefault() as OrderAttribute
orderby orderAttribute.Order
select property;
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Newobj, typeof(TestSubject).GetConstructors()[0]); // pushes a new instance of testsubject on the stack
il.Emit(OpCodes.Stloc_0); // pop the instance to local variable 0
foreach (var prop in properties)
{
il.Emit(OpCodes.Ldloc_0); // load local variable 0
il.Emit(OpCodes.Ldarg_0); // load argument 0 (the binary reader)
il.Emit(OpCodes.Callvirt, typeof(BinaryReader).GetMethod("ReadInt32", BindingFlags.Public | BindingFlags.Instance)); // call the binary reader method (ReadInt32)
il.Emit(OpCodes.Callvirt, prop.SetMethod); // call the setter of the property (instance of local variable 0 and return value of readint32)
il.Emit(OpCodes.Nop);
}
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Stloc_1);
var label = il.DefineLabel();
il.Emit(OpCodes.Br_S, label);
il.MarkLabel(label);
il.Emit(OpCodes.Ldloc_1); // push the test subject instance
il.Emit(OpCodes.Ret); // and return
var generator = (Load)method.CreateDelegate(typeof(Load));
var reader = new BinaryReader(new MemoryStream(new byte[] {1, 2, 3, 4, 0, 0, 0, 1}));
var test = generator(reader); // exception here
TestSubject类:
public class TestSubject
{
[Order]
public int Test1 { get; set; }
[Order]
public int Test2 { get; set; }
}
给我以下例外:
System.InvalidProgramException {“Die Common Language Runtime hat ein ungültigesM程序gefunden。“}
这有什么问题?
答案 0 :(得分:3)
您需要在使用本地之前声明它们。此外,代码可以简化(IL是在调试版本中生成的)。
il.DeclareLocal(typeof(TestSubject));
il.Emit(OpCodes.Newobj, typeof(TestSubject).GetConstructors()[0]); // pushes a new instance of testsubject on the stack
il.Emit(OpCodes.Stloc_0); // store the instance in local variable 0
foreach (var prop in properties)
{
il.Emit(OpCodes.Ldloc_0); // load local variable 0
il.Emit(OpCodes.Ldarg_0); // load argument 0 (the binary reader)
il.Emit(OpCodes.Callvirt, typeof(BinaryReader).GetMethod("ReadInt32", BindingFlags.Public | BindingFlags.Instance)); // call the binary reader method (ReadInt32)
il.Emit(OpCodes.Callvirt, prop.SetMethod); // call the setter of the property (instance of local variable 0 and return value of readint32)
}
il.Emit(OpCodes.Ldloc_0); // push the test subject instance
il.Emit(OpCodes.Ret); // and return
答案 1 :(得分:1)
您没有定义本地人。
此外,这里的IL来自调试模式输出。它比必要的更复杂。
反射发射几乎已经过时(某些情况下仍然需要)。使用表达式树生成这样的代码要容易得多。删除所有这些代码并将其替换为表达式树。