为IEnumerable<;调用“Current”;T>;使用反射.发出
本文关键字:gt 反射 发出 Current lt IEnumerable 调用 | 更新日期: 2023-09-27 17:59:15
请告知我如何构建IEnumerable<byte>
的属性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);
失败:
{"集合已修改;枚举操作可能无法执行。"}
变体2
当我按地址存储枚举器时(Ldloc_S->Ldloca_S)
......
il.Emit(OpCodes.Ldloca_S, lbBytesEnumerator);
il.EmitCall(OpCodes.Call, typeof(IEnumerator<byte>).GetProperty("Current").GetGetMethod(), null);
LocalBuilder lbControlByte = il.DeclareLocal(propertyInfo.PropertyType);
il.Emit(OpCodes.Stloc, lbControlByte);
它失败了:
{"试图读取或写入受保护的内存。这通常表明其他内存已损坏。"}
更新:
Enumerate数组返回不基于List的Enumerator,但它正在生成结果:
for (var i = 0; i < array.Length; i++)
yield return array[i];
如果要调用代码,必须使用Types和MethodInfos,而不是TypeBuilders和MethodBuilders。
因此,您需要创建Type(),然后使用该Type及其方法:
var generatedType = typeBuilder.CreateType();
var funcType = typeof(Func<,>).MakeGenericType(
generatedType, typeof(IEnumerable<string>));
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);