IL的新手...试图创建IL:
Dest CreateInstance(Source src)
{
Dest d = new Dest();
d.Test = src.Test;
return d;
}
这是我到目前为止所做的:
ConstructorInfo ctor = typeof(Dest).GetConstructors()[0];
DynamicMethod method = new DynamicMethod("CreateIntance", typeof(Dest),
new Type[] { typeof(Source) });
ILGenerator gen = method.GetILGenerator();
//gen.Emit(OpCodes.Ldarg_0);// source
gen.Emit(OpCodes.Newobj, ctor);// new Created
gen.Emit(OpCodes.Ret);
CreateCtor createdCtorDelegate;
createdCtorDelegate = (CreateCtor)method.CreateDelegate(typeof(CreateCtor));
这样运行如上...但是如果我取消注释Ldarg_0,我得到一个"这个操作可能会使运行时不稳定"当我试图给代表打电话时。
另外,我需要将Test成员复制一遍?假设它是一个基本类型。
谢谢!
编辑:
Source和Dest以及简单的POCO。
public class Source
{
public string S1 { get; set; }
public string S2 { get; set; }
public int I1 { get; set; }
public int I2 { get; set; }
public string S3 { get; set; }
public string S4 { get; set; }
public string S5 { get; set; }
}
public class Dest
{
public string S1 { get; set; }
public string S2 { get; set; }
public int I1 { get; set; }
public int I2 { get; set; }
public string S3 { get; set; }
public string S4 { get; set; }
public string S5 { get; set; }
}
编辑#2:现在,我有这个...仍然得到了不稳定的错误:
ConstructorInfo ctor = typeof(Dest).GetConstructors()[0];
DynamicMethod method = new DynamicMethod("CreateIntance", typeof(Dest),
new Type[] { typeof(Source) });
MethodInfo miSrc = tSource.GetProperty("S1").GetGetMethod();
MethodInfo miDest = tDest.GetProperty("S1").GetSetMethod();
ILGenerator gen = method.GetILGenerator();
gen.Emit(OpCodes.Newobj, ctor);// new Created
gen.Emit(OpCodes.Dup);
gen.Emit(OpCodes.Ldarg_1);// source
gen.Emit(OpCodes.Ldfld, miSrc);
gen.Emit(OpCodes.Stfld, miDest);
gen.Emit(OpCodes.Ret);
CreateCtor createdCtorDelegate;
createdCtorDelegate = (CreateCtor)method.CreateDelegate(typeof(CreateCtor));
Dest dd = createdCtorDelegate(s);
当我调用createdCtorDelegate时获取异常。
EDIT3:
ILSpy表明了这一点:
.method public hidebysig static
class ConsoleApplication3.Dest Test (
class ConsoleApplication3.Source s
) cil managed
{
// Method begins at RVA 0x2148
// Code size 26 (0x1a)
.maxstack 2
.locals init (
[0] class ConsoleApplication3.Dest,
[1] class ConsoleApplication3.Dest
)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication3.Dest::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldarg.0
IL_0009: callvirt instance string ConsoleApplication3.Source::get_S1()
IL_000e: callvirt instance void ConsoleApplication3.Dest::set_S1(string)
IL_0013: nop
IL_0014: ldloc.0
IL_0015: stloc.1
IL_0016: br.s IL_0018
IL_0018: ldloc.1
IL_0019: ret
} // end of method Program::Test
所以,我已将我的代码调整为:
ConstructorInfo ctor = typeof(Dest).GetConstructors()[0];
DynamicMethod method = new DynamicMethod("CreateIntance", typeof(Dest),
new Type[] { typeof(Source) });
MethodInfo miSrc = tSource.GetProperty("S1").GetGetMethod();
MethodInfo miDest = tDest.GetProperty("S1").GetSetMethod();
ILGenerator gen = method.GetILGenerator();
gen.Emit(OpCodes.Newobj, ctor);// new Created
gen.Emit(OpCodes.Stloc_0);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Callvirt, miSrc);
gen.Emit(OpCodes.Callvirt, miDest);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Stloc_1);
gen.Emit(OpCodes.Ldloc_1);
gen.Emit(OpCodes.Ret);
CreateCtor createdCtorDelegate;
createdCtorDelegate = (CreateCtor)method.CreateDelegate(typeof(CreateCtor));
仍然崩溃:( ...
答案 0 :(得分:1)
...但如果我取消注释Ldarg_0 ......
您的方法应该返回一个值,这意味着当达到ret
指令时,堆栈必须包含一个项目。 newobj
指令将创建新对象并将对它的引用加载到堆栈中,因此如果在到达ret
之前向堆栈添加更多项而不消耗它们,则代码无效。
我需要什么来复制测试成员?
获取有效IL指令的最快方法是使用高级语言,以及编译器和反编译器。 当你这样做时,你会得到这样的东西:
IL_0000: newobj instance void Dest::.ctor() //create the new object
IL_0005: dup //duplicate the reference
IL_0006: ldarg.1 //load the object to copy from
IL_0007: ldfld object Source::Test //load the value from the old objects field
IL_000c: stfld object Dest::Test //safe the value to the new objects field
IL_0011: ret //one reference of the new object is still on the stack
答案 1 :(得分:0)
您的上一个代码接近正确,您只需声明要使用的本地代码:
ILGenerator gen = method.GetILGenerator();
gen.DeclareLocal(typeof(Dest));
另请注意,最后一对stloc.1
,ldloc.1
是不必要的,并且是在调试模式下编译代码的结果。在检查CIL时,始终在Release中编译代码,因为代码更短,更容易阅读。
你的方法的第二个版本也几乎是正确的,问题在于:
gen.Emit(OpCodes.Ldarg_1);// source
没有"参数1",因为参数列表从0开始(对于静态方法,实例方法具有this
作为参数0)。修复很简单:
gen.Emit(OpCodes.Ldarg_0);// source