gpt4 book ai didi

c# - 在常规阵列上测试 foreach 框/拆箱?

转载 作者:行者123 更新时间:2023-12-05 00:50:21 27 4
gpt4 key购买 nike

我已阅读 this excellent question关于如何定期int[]foreach 下处理(框与否)循环。

Array确实实现了非泛型 IEnumerable所以它必须使用 object内部(而不是 int)

但它turns out那 - 在运行时它实际上被处理为 IEnumerable<T>

如何通过简单的 C# 测试/证明(没有拳击)它代码? (而不是通过阅读 IL。)

最佳答案

我喜欢@phoog 的回答,所以只是为了好玩:)

助手类

public static class ILUtils
{
private static Dictionary<short, OpCode> s_opcodes = new Dictionary<short, OpCode>();

static ILUtils()
{
FieldInfo[] opCodeFields = typeof(OpCodes).GetFields(BindingFlags.Public | BindingFlags.Static);
foreach (FieldInfo opCodeField in opCodeFields)
{
if (opCodeField.FieldType != typeof(OpCode))
continue;

OpCode opcode = (OpCode)opCodeField.GetValue(null);
s_opcodes.Add(opcode.Value, opcode);
}
}

public static bool ContainsOpcodes(MethodInfo methodInfo, IEnumerable<OpCode> targetOpCodes)
{
MethodBody methodBody = methodInfo.GetMethodBody();

using (BinaryReader ilReader = new BinaryReader(new MemoryStream(methodBody.GetILAsByteArray())))
{
while (ilReader.BaseStream.Position < ilReader.BaseStream.Length)
{
short opCodeValue = ilReader.ReadByte();
if (opCodeValue == 0xfe)
opCodeValue = (short)(opCodeValue << 8 | ilReader.ReadByte());

OpCode opCode = s_opcodes[opCodeValue];
if (targetOpCodes.Contains(opCode))
return true;

int argumentSize = 4;
if (opCode.OperandType == OperandType.InlineNone)
argumentSize = 0;
else if (opCode.OperandType == OperandType.ShortInlineBrTarget || opCode.OperandType == OperandType.ShortInlineI || opCode.OperandType == OperandType.ShortInlineVar)
argumentSize = 1;
else if (opCode.OperandType == OperandType.InlineVar)
argumentSize = 2;
else if (opCode.OperandType == OperandType.InlineI8 || opCode.OperandType == OperandType.InlineR)
argumentSize = 8;
else if (opCode.OperandType == OperandType.InlineSwitch)
{
int num = ilReader.ReadInt32();
argumentSize = (int)(4 * num + 4);
}

ilReader.BaseStream.Position += argumentSize;
}
}

return false;
}
}

使用示例

private static void BoxingForEach()
{
IEnumerable foo = (IEnumerable)new int[10];
foreach (int i in foo) ;
}

private static void NoBoxingForEach()
{
int[] foo = new int[10];
foreach (int i in foo) ;
}

static void Main(string[] args)
{
MethodInfo boxingForEach = typeof(Program).GetMethod("BoxingForEach", BindingFlags.Static | BindingFlags.NonPublic);
MethodInfo noBoxingForEach = typeof(Program).GetMethod("NoBoxingForEach", BindingFlags.Static | BindingFlags.NonPublic);

Console.WriteLine("BoxingForEach is using boxing: {0}",
ILUtils.ContainsOpcodes(boxingForEach, new[] { OpCodes.Box, OpCodes.Unbox, OpCodes.Unbox_Any }));

Console.WriteLine("NoBoxingForEach is using boxing: {0}",
ILUtils.ContainsOpcodes(noBoxingForEach, new[] { OpCodes.Box, OpCodes.Unbox, OpCodes.Unbox_Any }));
}

结果

BoxingForEach is using boxing: True

NoBoxingForEach is using boxing: False

关于c# - 在常规阵列上测试 foreach 框/拆箱?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14038264/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com