我正在使用Visual Studio 2010 SP1 Ultimate进行C#类库项目(.net 4)的开发,我对某些事情很好奇...
给定以下方法:
我从代码分析中得到了如下的警告:
更新:
这是“未优化”版本的IL(在此版本中,代码分析得到了正确的结果):
这里是针对优化版本的翻译(它会出错):
我看到在抛出操作之前有一堆额外的调用,但是说实话 - 我不知道它们是做什么的!
给定以下方法:
public void DoSomethingBrilliant(int input)
{
if (input == int.MaxValue)
throw new ArgumentOutOfRangeException("input");
input++;
Console.WriteLine(input);
}
我从代码分析中得到了如下的警告:
我想了想,觉得这有点奇怪,因为我已经通过在开头抛出异常来检查CA2233 : Microsoft.Usage : 请在“Test.DoSomethingBrilliant(int)”中修正操作“input+1”可能会溢出的问题。
input++
操作是否会溢出,但我将其改成了这样:public void DoSomethingBrilliant(int input)
{
if (input >= int.MaxValue)
throw new ArgumentOutOfRangeException("input");
input++;
Console.WriteLine(input);
}
然后警告果然消失了。
现在我的小脑袋很困惑,因为我得到的参数是一个int,那么为什么检查它是否大于整数允许的最大值会有任何价值呢?
然后我回到了原来的代码,并切换到了调试模式,没有警告就编译成功了!越来越奇怪了...
我检查了调试和发布之间的差异,发现如果我选中了优化代码选项,那么代码分析中的警告就会弹出。
所以优化会导致某些情况下需要检查是否大于int.MaxValue。嗯?为什么?我是不是太迟钝了?优化做了什么,使得我可能会得到一个比接受int的方法所允许的int.MaxValue还要大的int参数呢?
还是说这只是代码分析功能中的一个错误吗?更新:
这是“未优化”版本的IL(在此版本中,代码分析得到了正确的结果):
.method public hidebysig instance void DoSomethingBrilliant(int32 input) cil managed
{
// Code size 40 (0x28)
.maxstack 2
.locals init ([0] bool CS$4$0000)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldc.i4 0x7fffffff
IL_0007: ceq
IL_0009: ldc.i4.0
IL_000a: ceq
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: brtrue.s IL_001b
IL_0010: ldstr "input"
IL_0015: newobj instance void [mscorlib]System.ArgumentOutOfRangeException::.ctor(string)
IL_001a: throw
IL_001b: ldarg.1
IL_001c: ldc.i4.1
IL_001d: add
IL_001e: starg.s input
IL_0020: ldarg.1
IL_0021: call void [mscorlib]System.Console::WriteLine(int32)
IL_0026: nop
IL_0027: ret
} // end of method Test::DoSomethingBrilliant
这里是针对优化版本的翻译(它会出错):
.method public hidebysig instance void DoSomethingBrilliant(int32 input) cil managed
{
// Code size 31 (0x1f)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldc.i4 0x7fffffff
IL_0006: bne.un.s IL_0013
IL_0008: ldstr "input"
IL_000d: newobj instance void [mscorlib]System.ArgumentOutOfRangeException::.ctor(string)
IL_0012: throw
IL_0013: ldarg.1
IL_0014: ldc.i4.1
IL_0015: add
IL_0016: starg.s input
IL_0018: ldarg.1
IL_0019: call void [mscorlib]System.Console::WriteLine(int32)
IL_001e: ret
} // end of method Test::DoSomethingBrilliant
我看到在抛出操作之前有一堆额外的调用,但是说实话 - 我不知道它们是做什么的!
==
是否以某种奇怪的方式进行了优化。你有查看过 IL 吗? - Jon Skeet