如何定义已检查整数的列表

我有一个整数列表定义为List myIntList = new List(); 像往常一样,我将使用myIntList.Add()方法为列表添加值。 我面临的问题是列表中的值是动态的(一些计算的结果),可能超过整数可以容纳的最大值。

请考虑以下情形:

  int x = int.MaxValue; myIntList.Add(x + 1); 

这将在列表中添加-2147483648而不是抛出exception。 我需要在这里抛出exception。 我知道myIntList.Add(checked(x + 1)); 将完美地完成工作,或者我甚至可以将myIntList.Add()括在checked{} ,如下所示:

  checked { myIntList.Add(12); myIntList.Add(int.MaxValue); myIntList.Add(x + 1); } 

这是我的问题这有什么替代方案吗? 我可以定义已检查整数的列表吗? 如何在列表中添加的值超出限制的情况下创建引发exception的列表?

更新:

谢谢大家的回复,大多数人建议在将它们添加到列表之前检查整数(如果它超出边界则抛出exception)。 这与我通过给定的片段checked{// add elements }所做的相同,它将抛出exception而不进行任何复杂的条件检查。

你正在错误的层面解决问题。 首先,你的计算 – 它返回某种类型的值 – intlong等。不应该检查溢出吗? 它没有溢出,但返回的long ,例如?

如果在添加到容器时仍应执行此操作,则可以创建如下所示的检查列表:

 class CheckedList : List { public void Add(long x) { if (int.MaxValue < x || int.MinValue > x) throw new ArgumentOutOfRangeException("Invalid"); var i = (int) x; base.Add(i); } } 

基本理念

假设你想要一个这样的行为:

 List myIntList = new List(); CheckedInt check1 = int.MaxValue; CheckedInt check2 = 1; myIntList.Add(check1 + check2); //exception occurs! 

最简洁的方法之一(使得诸如x + y类的操作代码可以保留但能够同时throwing exception )将是使用重载运算符 定义自己的CheckedInt (基于int )。


履行

结构

CheckedInt struct将是这样的:

 public struct CheckedInt { private int Value { get; set; } public CheckedInt(int value) : this() { Value = value; } public static implicit operator CheckedInt(int me) { return new CheckedInt(me); } public static CheckedInt operator +(CheckedInt lhs, CheckedInt rhs) { double testResult = (double)lhs.Value + (double)rhs.Value; if (testResult > int.MaxValue || testResult < int.MinValue) throw new MyCheckedIntException(); return new CheckedInt(lhs.Value + rhs.Value); //note that direct lhs+rhs will cause StackOverflow } public static CheckedInt operator -(CheckedInt lhs, CheckedInt rhs) { double testResult = (double)lhs.Value - (double)rhs.Value; if (testResult > int.MaxValue || testResult < int.MinValue) throw new MyCheckedIntException(); return new CheckedInt(lhs.Value - rhs.Value); //note that direct lhs-rhs will cause StackOverflow } public static CheckedInt operator *(CheckedInt lhs, CheckedInt rhs) { double testResult = (double)lhs.Value * (double)rhs.Value; if (testResult > int.MaxValue || testResult < int.MinValue) throw new MyCheckedIntException(); return new CheckedInt(lhs.Value * rhs.Value); //note that direct lhs*rhs will cause StackOverflow } public static CheckedInt operator /(CheckedInt lhs, CheckedInt rhs) { double testResult = (double)lhs.Value / (double)rhs.Value; if (testResult > int.MaxValue || testResult < int.MinValue) throw new MyCheckedIntException(); return new CheckedInt(lhs.Value / rhs.Value); //note that direct lhs-rhs will cause StackOverflow } //Add any other overload that you want public override string ToString() { //example return Value.ToString(); } public bool Equals(CheckedInt otherInt) { //example return Value == otherInt.Value; } } 

例外

你也可以定义自己的例外。

 public class MyCheckedIntException : Exception { public MyCheckedIntException() { //put something } public MyCheckedIntException(string message) : base(message) { //put something } public MyCheckedIntException(string message, Exception inner) : base(message, inner) { //put something } 

现在,你有一个真正的CheckedInt List


使用

只需像这样使用它:

 CheckedInt check1 = int.MaxValue; CheckedInt check2 = 1; 

而这句话:

 List myIntList = new List(); myIntList.Add(check1 + check2); //exception! 

将为您抛出exceptionMyCheckedIntException


扩展,清洁外观

如果您想像以下任何一个一样使用它:

 myIntList.Add(check1 + 1); //note that `1` is not type of checked integer myIntList.Add(1 + check1); //note that `1` is not type of checked integer 

然后只需将overloading添加到operator overloads

 public static CheckedInt operator +(CheckedInt lhs, int rhs) { //note the type of rhs double testResult = (double)lhs.Value + (double)rhs; if (testResult > int.MaxValue || testResult < int.MinValue) throw new MyCheckedIntException(); return new CheckedInt(lhs.Value + rhs); //note that direct lhs+rhs will cause StackOverflow } public static CheckedInt operator +(int lhs, CheckedInt rhs) { //not the type of lhs double testResult = (double)lhs + (double)rhs.Value; if (testResult > int.MaxValue || testResult < int.MinValue) throw new MyCheckedIntException(); return new CheckedInt(lhs + rhs.Value); //note that direct lhs+rhs will cause StackOverflow } 

您也可以为所有其他运营商做同样的事。

您无法检查该总和的结果是否超出范围,因为如果您只有结果,则您没有所有必需的数据。 如果你的问题确实是溢出的int ,你有几个选择:

  1. 您可以为列表创建自己的类,如@tenbits建议。
  2. 您可以为列表创建扩展方法。
    2a)创建与选项1中相同的Add方法。
    2b)创建方法,在其中添加数字并决定(你必须知道你想对这些数字做什么操作,但是将int改成long等不应该有任何问题):

     public static void Add(this List list, int value, int otherValue) { if ((long)value + otherValue > int.MaxValue || (long)value + otherValue < int.MinValue) { throw new ArgumentOutOfRangeException("Integer overflow"); } else { list.Add(value + otherValue); } } 

我认为你可以创建一些其他的例子,但没有太大的区别。

然而,重要的是要注意,使用checked关键字(从我尝试过)始终是最快的解决方案。 实际上它几乎和没有检查的简单插入一样快,所以如果没有严重的理由为什么不使用checked关键字,我必须推荐它。

在添加之前,我会( 参考 ):

Int.TryParse(string,int)

因此,如果由于> int.MaxValue或

希望这可以帮助

只需你可以解析并将值转换为更长的类型:

 List myIntList = new List(); int x = int.MaxValue; myIntList.Add(int.Parse(((long)x + 1).ToString())); 

它会抛出System.OverflowException。

 myIntList.Add(int.Parse(((long)x - 1).ToString())); 

否则将添加整数值。

有一点需要考虑。 你在这里的实际意图是什么? 我的意思是:如果您不想添加导致溢出的结果,为什么在实际尝试将它们添加到列表时检查它们? 你怎么处理导致溢出的结果? 你把它们添加到其他列表中吗? 或者你忽略它们?

我要做的是在实际调用List.Add()之前检查溢出。 这样,您就可以更好地控制数据流。 您可以忽略,记录,替换等溢出的数据。

只需要考虑一些事情。

2种处理方式:

  1. 使用checked/unchecked包裹您的代码(正如您现在所做的那样)
  2. 使用/ checked编译器选项(默认情况下关闭)。

这是我的问题这有什么替代方案吗? 我可以定义已检查整数的列表吗? 如何在列表中添加的值超出限制的情况下创建引发exception的列表?

在传递给List之前计算中发生溢出,因此List类不可能检测到这种溢出。 溢出这个词在这里用得最严格。

替代方案基于您已经知道的内容,即使用已checked上下文。 您可以使用编译选项/选中 ,这可以减轻您使用关键字的麻烦。 请注意,需要使用此选项编译调用代码(而不是List代码)。

简短的回答是:不,你不能。

还有其他“解决方法”在其他答案中没有完全符合您的要求,但这里是您不能做您想做的事情的基本解释:

编译时,代码基本上会分解为这样的代码:

 int x = int.MaxValue; int temp = x + 1; list.Add(temp); 

编译器只是帮助您保存击键,而不是强制您为每个子表达式创建命名临时变量。 因为必须创建那些临时变量。

要理解为什么必须在调用Add(...)方法之前计算x + 1您需要了解CPU如何执行代码,一些基本程序集和一些编译概念。 所有这些都超出了这个问题的范围 – 如果你想了解更多关于它的问题,可以提出一个新问题。

尝试介绍IntWrapper类,它负责添加两个int。

 public static class IntWrapper { public static Int32 Add(this Int32 left, Int32 right) { if ((Int64)left + (Int64)right > (Int64)Int32.MaxValue) throw new ArgumentOutOfRangeException(); return left + right; } } 

使用Add方法添加两个整数。

在存储到列表中之前,需要检测计算结果中的溢出。

假设x和y为正数:

if(x + y)