【问题标题】:How can i define a List of checked integers如何定义已检查整数列表
【发布时间】:2016-01-12 13:48:02
【问题描述】:

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

考虑以下场景:

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

这会将-2147483648 添加到列表中,而不是引发异常。我需要在这里抛出一个异常。我知道myIntList.Add(checked(x + 1)); 可以完美地完成这项工作,或者我什至可以将 myIntList.Add() 包含在checked{} 中,如下所示:

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

这是我的问题有没有其他选择?我可以定义一个检查整数列表吗?如果添加到列表中的值超过限制,如何制作引发异常的列表?

更新:

感谢大家的回复,大多数人建议在将整数添加到列表之前检查整数(如果超出边界则抛出异常)。这与我通过给定的 sn-p checked{// add elements } 所做的相同,它将抛出异常而无需任何复杂的条件检查。

【问题讨论】:

  • 能否请您说明原因。
  • 这个thread 可能很有用。
  • @un-lucky 你不能用Int64 吗?
  • @KMB:我实际使用的那个 (checked{})
  • 但是List<> 在尝试添加整数之前如何检查整数发生了什么?

标签: c# list exception integer-overflow


【解决方案1】:

您在错误的层面上解决了问题。首先,您的计算 - 它返回某种类型的值 - intlong 等。不应该在那里检查溢出吗?是不是没有溢出,而是返回long之类的?

如果在添加到容器时仍然应该这样做,您可以像这样创建您的检查列表:

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

【讨论】:

    【解决方案2】:

    基本思路

    假设您想要这样的行为:

    List<CheckedInt> myIntList = new List<CheckedInt>();    
    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
    }
    

    现在,您拥有真正的ListCheckedInt



    用途

    像这样简单地使用它:

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

    还有这句话:

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

    将为您抛出异常MyCheckedIntException



    扩展,让外观更简洁

    如果你想像下面这样使用它:

    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
    }
    

    您可以对所有其他运算符执行同样的操作。

    【讨论】:

      【解决方案3】:

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

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

        public static void Add(this List<int> 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关键字,我不得不推荐它。

      【讨论】:

        【解决方案4】:

        在添加之前,我会(ref):

        Int.TryParse(string, int)

        因此如果因为> int.MaxValue 或

        希望对你有帮助

        【讨论】:

          【解决方案5】:

          您只需解析并将值转换为更大的类型(如 long)即可:

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

          它会抛出 System.OverflowException。

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

          否则将添加整数值。

          【讨论】:

          • 能否请您包括“这个优于checked{// add elements }的优势
          【解决方案6】:

          需要考虑一件事。你在这里的实际意图是什么?我的意思是:如果您不想添加导致溢出的结果,为什么在实际尝试将它们添加到列表时检查它们?您如何处理导致溢出的结果?您是否将它们添加到其他列表中?还是你不理他们?

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

          只是一些需要考虑的事情。

          【讨论】:

          • 您为什么要发布这些问题作为答案?最好是评论
          【解决方案7】:

          两种处理方式:

          1. checked/unchecked 包装您的代码(就像您现在所做的那样)
          2. 使用/checked 编译器选项(默认关闭)。

          【讨论】:

            【解决方案8】:

            这是我的问题 有什么替代方案吗?我可以定义一个 检查整数列表?我怎样才能制作一个抛出一个列表 添加到列表中的值超过 限制?

            溢出发生在计算传递给 List 之前,因此 List 类不可能检测到这种溢出。溢出一词在这里是按其最严格的意义使用的。

            替代方法基于您已经知道的,即使用checked 上下文。您可以使用编译选项/checked,这可能会使您免于使用关键字。注意调用代码(不是List代码)需要用这个选项编译。

            【讨论】:

              【解决方案9】:

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

              还有其他“解决方法”并不能完全按照您在其他答案中的要求做,但这里是您为什么不能做您想做的事情的基本解释:

              当你编译它时,你的代码基本上会分解成这样:

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

              编译器只是通过不强制您为每个子表达式创建命名临时变量来帮助您节省击键。因为那些临时变量必须被创建。

              要了解为什么x + 1 必须在调用Add(...) 方法之前计算,您需要了解CPU 如何执行代码、一些基本汇编和一些编译概念。所有这些都超出了这个问题的范围 - 如果您想了解更多信息,请提出一个新问题。

              【讨论】:

                【解决方案10】:

                尝试引入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方法将两个整数相加。

                【讨论】:

                  【解决方案11】:

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

                  假设 x 和 y 为正数:

                  如果 (x + y)

                  【讨论】:

                    猜你喜欢
                    • 2012-04-15
                    • 2010-12-03
                    • 2013-01-14
                    • 2012-05-12
                    • 2017-07-05
                    • 2022-08-18
                    • 2014-08-25
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多