C# 为IEnumerable调用'Current'<;T>;使用Reflection.Emit
请告知如何构建C# 为IEnumerable调用'Current'<;T>;使用Reflection.Emit,c#,reflection.emit,il,C#,Reflection.emit,Il,请告知如何构建IEnumerable的属性Current和MoveNext的调用 目标 我想买一些像这样的东西: var bytesEnumerator = byteArray.EnumerateArray(); var controlByte = bytesEnumerator.Current; bytesEnumerator.MoveNext(); 变式1 以下是代码: LocalBuilder lbBytesEnumerator = il.DeclareLocal(typeof (IEn
IEnumerable
的属性Current
和MoveNext
的调用
目标
我想买一些像这样的东西:
var bytesEnumerator = byteArray.EnumerateArray();
var controlByte = bytesEnumerator.Current;
bytesEnumerator.MoveNext();
变式1
以下是代码:
LocalBuilder lbBytesEnumerator = il.DeclareLocal(typeof (IEnumerator<byte>));
// Get enumerator over bytes
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, typeof(ByteConverter).GetMethod("EnumerateArray"), new[] { typeof(byte[]) } );
il.Emit(OpCodes.Stloc, lbBytesEnumerator);
.......
il.Emit(OpCodes.Ldloc_S, lbBytesEnumerator);
il.EmitCall(OpCodes.Call, typeof(IEnumerator<byte>).GetProperty("Current").GetGetMethod(), null);
LocalBuilder lbControlByte = il.DeclareLocal(propertyInfo.PropertyType);
il.Emit(OpCodes.Stloc, lbControlByte);
// Enumerator Move Next
il.Emit(OpCodes.Ldloc_S, lbBytesEnumerator);
il.EmitCall(OpCodes.Call, typeof(List<byte>.Enumerator).GetMethod("MoveNext"), null);
il.Emit(OpCodes.Pop);
LocalBuilder lbBytesEnumerator=il.DeclareLocal(typeof(IEnumerator));
//获取超过字节的枚举数
il.Emit(操作码.Ldarg_0);
EmitCall(OpCodes.Call,typeof(ByteConverter).GetMethod(“EnumerateArray”),新的[]{typeof(byte[])};
il.Emit(操作码.Stloc,lbBytesEnumerator);
.......
il.Emit(操作码.Ldloc_S,lbBytesEnumerator);
EmitCall(OpCodes.Call,typeof(IEnumerator).GetProperty(“当前”).getMethod(),null);
LocalBuilder lbControlByte=il.DeclareLocal(propertyInfo.PropertyType);
il.Emit(opcode.Stloc,lbControlByte);
//枚举器下一步移动
il.Emit(操作码.Ldloc_S,lbBytesEnumerator);
EmitCall(OpCodes.Call,typeof(List.Enumerator).GetMethod(“MoveNext”),null);
发射(操作码Pop);
失败,原因是:
{“集合已修改;枚举操作可能无法执行。”}
变式2
当我按地址存储枚举数时(Ldloc\u S->Ldloca\u S)
。。。。。。
il.Emit(操作码.Ldloca_S,lbBytesEnumerator);
EmitCall(OpCodes.Call,typeof(IEnumerator).GetProperty(“当前”).getMethod(),null);
LocalBuilder lbControlByte=il.DeclareLocal(propertyInfo.PropertyType);
il.Emit(opcode.Stloc,lbControlByte);
它失败于:
{“试图读取或写入受保护的内存。这通常表示其他内存已损坏。”}
更新:
Enumerate数组返回的枚举数不基于列表,但会产生以下结果:
for (var i = 0; i < array.Length; i++)
yield return array[i];
for(变量i=0;i
如果要调用代码,必须使用类型和方法信息,而不是类型生成器和方法生成器
因此,您需要创建类型(),然后使用该类型及其方法:
var generatedType = typeBuilder.CreateType();
var funcType = typeof(Func<,>).MakeGenericType(
generatedType, typeof(IEnumerable<string>));
var d = generatedType.GetMethod("MoveNext").CreateDelegate(funcType);
var generatedType=typeBuilder.CreateType();
var funcType=typeof(Func).MakeGenericType(
generatedType,typeof(IEnumerable));
var d=generatedType.GetMethod(“MoveNext”).CreateDelegate(funcType);
固定代码:
// Control byte
il.Emit(OpCodes.Ldloc, lbBytesEnumerator);
il.EmitCall(OpCodes.Callvirt, typeof(IEnumerator<byte>).GetProperty("Current").GetGetMethod(), null);
LocalBuilder lbControlByte = il.DeclareLocal(propertyInfo.PropertyType);
il.Emit(OpCodes.Stloc, lbControlByte);
// Enumerator Move Next
il.Emit(OpCodes.Ldloc, lbBytesEnumerator);
il.EmitCall(OpCodes.Callvirt, typeof(IEnumerator).GetMethod("MoveNext"), null);
il.Emit(OpCodes.Pop);
//控制字节
il.Emit(操作码.Ldloc,lbBytesEnumerator);
EmitCall(OpCodes.Callvirt,typeof(IEnumerator).GetProperty(“当前”).getMethod(),null);
LocalBuilder lbControlByte=il.DeclareLocal(propertyInfo.PropertyType);
il.Emit(opcode.Stloc,lbControlByte);
//枚举器下一步移动
il.Emit(操作码.Ldloc,lbBytesEnumerator);
EmitCall(OpCodes.Callvirt,typeof(IEnumerator.GetMethod(“MoveNext”),null);
发射(操作码Pop);
我怀疑第一个错误是因为您在调用GetEnumerator
-之后修改了列表,在指示的代码中,
如果您用C#编写代码,编译它,然后反汇编它会怎么样?也许这可以说明如何对其进行编码?@JonSkeet:Bit这将不同于其他地方使用的IEnumerator
,而lbBytesEnumerator
被声明为。(由于没有使用CallVirt
,这可能会导致异常)。顺便说一句,除非你真的知道自己在做什么,否则通常需要使用CallVirt
。@leppie:我敢说会的。我只是回答了你关于类型的问题:)
// Control byte
il.Emit(OpCodes.Ldloc, lbBytesEnumerator);
il.EmitCall(OpCodes.Callvirt, typeof(IEnumerator<byte>).GetProperty("Current").GetGetMethod(), null);
LocalBuilder lbControlByte = il.DeclareLocal(propertyInfo.PropertyType);
il.Emit(OpCodes.Stloc, lbControlByte);
// Enumerator Move Next
il.Emit(OpCodes.Ldloc, lbBytesEnumerator);
il.EmitCall(OpCodes.Callvirt, typeof(IEnumerator).GetMethod("MoveNext"), null);
il.Emit(OpCodes.Pop);