为IEnumerable<;调用“Current”;T>;使用反射.发出

本文关键字:gt 反射 发出 Current lt IEnumerable 调用 | 更新日期: 2023-09-27 17:59:15

请告知我如何构建IEnumerable<byte>的属性CurrentMoveNext的调用。

目标

我想要一些类似的东西:

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];

为IEnumerable<;调用“Current”;T>;使用反射.发出

如果要调用代码,必须使用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);