通过System.Linq.Enumerable在DotPeek中查看,我注意到一些方法是使用[__DynamicallyInvokable]属性调整的.
这个属性扮演什么角色?它是由DotPeek添加的还是它扮演另一个角色,也许告诉编译器如何最好地优化方法?
在几种现代编程语言(包括C++,Java和C#)中,该语言允许在运行时发生整数溢出,而不会引发任何类型的错误条件.
例如,考虑这个(人为的)C#方法,它没有考虑上溢/下溢的可能性.(为简洁起见,该方法也不处理指定列表为空引用的情况.)
//Returns the sum of the values in the specified list.
private static int sumList(List<int> list)
{
int sum = 0;
foreach (int listItem in list)
{
sum += listItem;
}
return sum;
}
Run Code Online (Sandbox Code Playgroud)
如果调用此方法如下:
List<int> list = new List<int>();
list.Add(2000000000);
list.Add(2000000000);
int sum = sumList(list);
Run Code Online (Sandbox Code Playgroud)
sumList()方法中将发生溢出(因为intC#中的类型是32位有符号整数,并且列表中值的总和超过了最大32位有符号整数的值).sum变量的值为-294967296(不是值4000000000); 这很可能不是sumList方法的(假设的)开发人员所期望的.
显然,开发人员可以使用各种技术来避免整数溢出的可能性,例如使用类似Java的类型BigInteger,或者使用C#中的checked关键字和/checked编译器开关.
但是,我感兴趣的问题是为什么这些语言默认设计为允许整数溢出首先发生,而不是例如在运行时执行操作时引发异常,从而导致溢出.看起来这种行为有助于避免在编写执行可能导致溢出的算术运算的代码时开发人员忽略解释溢出可能性的情况下的错误.(这些语言可能包含类似"未经检查"的关键字,它可以指定允许发生整数溢出而不会引发异常的块,在开发人员明确意图该行为的情况下; C#实际上确实有这个. )
答案简单归结为性能 - 语言设计者不希望他们各自的语言默认具有"慢"算术整数运算,其中运行时需要做额外的工作来检查是否发生溢出,在每个适用的算术上操作 - 这种性能考虑超过了在无意溢出发生时避免"无声"故障的价值?
除了性能考虑之外,还有其他原因可以做出这种语言设计决策吗?
可能重复:
默认情况下,为什么语言不会引发整数溢出错误?
为什么C#默认不使用算术溢出检查?
我认为发生异常通常会更好,这样就不会模糊错误.我知道利用发生的"包装"行为偶尔会有用,但unchecked在这些情况下可以使用关键字来明确意图.
我希望这个决定是故意做出的,也许是为了增加与其他基于C语言的兼容性.
我正在使用LinqPad测试一些东西,并惊讶于以下代码没有产生异常:
ulong lSmallValue = 5;
ulong lBigValue = 10;
ulong lDifference = lSmallValue - lBigValue;
Console.WriteLine(lDifference);
Console.WriteLine((long)lDifference);
Run Code Online (Sandbox Code Playgroud)
这会产生以下输出:
18446744073709551611
-5
Run Code Online (Sandbox Code Playgroud)
幸运的是,我希望这种行为,但我认为这会导致OverflowException被抛出.
在以下条件下,在运行时抛出OverflowException:
- 算术运算产生的结果超出了操作返回的数据类型的范围.
- 转换或转换操作尝试执行缩小转换,并且源数据类型的值超出目标数据类型的范围.
为什么操作不lSmallValue - lBigValue属于第一类?