我试图在运行时以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 hereTestSubject类:
public class TestSubject
{
[Order]
public int Test1 { get; set; }
[Order]
public int Test2 { get; set; }
}给我以下例外:
System.InvalidProgramException {“在ungültiges编程中使用通用语言运行时帽子”}
这有什么问题吗?
发布于 2016-07-31 15:12:45
在使用它们之前,您需要声明本地值。此外,代码可以简化( 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发布于 2016-07-31 15:04:03
你没有定义当地人。
另外,这里的IL来自调试模式输出。这比必要的要复杂一些。
反射发出几乎已经过时(在某些情况下仍然需要)。使用表达式树生成这样的代码要容易得多。删除所有这些代码并将其替换为表达式树。
https://stackoverflow.com/questions/38685240
复制相似问题