简体   繁体   English

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

[英]How can i define a List of checked integers

I have a List of Integers defined as List<int> myIntList = new List<int>(); 我有一个整数列表定义为List<int> myIntList = new List<int>(); As usual I will add value to the list using myIntList.Add() method. 像往常一样,我将使用myIntList.Add()方法为列表添加值。 The problem I am facing is that the values in the list are dynamic(result of some calculation) that may exceed the maximum value that an integer can hold. 我面临的问题是列表中的值是动态的(一些计算的结果),可能超过整数可以容纳的最大值。

Consider the following scenario: 请考虑以下情形:

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

This will add -2147483648 to the list instead of throwing an exception. 这将在列表中添加-2147483648而不是抛出异常。 I need to throw an exception here. 我需要在这里抛出异常。 I know myIntList.Add(checked(x + 1)); 我知道myIntList.Add(checked(x + 1)); will do the job perfectly or I can even enclose the myIntList.Add() within checked{} like the following: 将完美地完成工作,或者我甚至可以将myIntList.Add()括在checked{} ,如下所示:

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

Here is my question Is there any alternative for this? 这是我的问题这有什么替代方案吗? Can I define a list of checked integers? 我可以定义已检查整数的列表吗? How can I make a list that throws an exception in the case where the value added to the list exceeds the limit? 如何在列表中添加的值超出限制的情况下创建引发异常的列表?

Updates: 更新:

Thank you all for the response, most of you people suggest to check the integer (Throw exception if it outside the boundary) before adding them to the list. 谢谢大家的回复,大多数人建议在将它们添加到列表之前检查整数(如果它超出边界则抛出异常)。 This is the same what i done through the given snippet checked{// add elements } it will throw exception without any complex condition checking. 这与我通过给定的片段checked{// add elements }所做的相同,它将抛出异常而不进行任何复杂的条件检查。

You are solving the problem on the wrong level. 您正在错误的级别上解决问题。 First of all, your calculation - it returns the value of some type - int , long etc. Should not it be there checked for the overflow? 首先,你的计算 - 它返回某种类型的值 - intlong等。不应该检查溢出吗? Is it not overflowed, but returns long , for example? 它没有溢出,但回报long ,例如?

If this still should be done while adding to the container, you can create your check list like this: 如果在添加到容器时仍应执行此操作,则可以创建如下所示的检查列表:

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);
    }
}

Basic Idea 基本理念

Assuming you want a behavior such as this: 假设您想要这样的行为:

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

One of the cleanest way to do that (such that the operation code such as x + y can be retained but capable of throwing exception at the same time) would be to define your own CheckedInt (based on int ) with overloaded operators . 最简洁的方法之一(这样可以保留x + y等操作代码但能够同时throwing exception )将是使用重载运算符 定义自己的CheckedInt (基于int )。



Implementation 履行

The struct 结构

The CheckedInt struct would be something like this: 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;
    }
}


The Exception 例外

And you may define your own exception too. 你也可以定义自己的例外。

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
}

And now, you have a real List of CheckedInt with you. 现在,你有一个真正的CheckedInt List



The Use 使用

Simply use it like this: 只需使用它:

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

And this statement: 而这句话:

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

Will throw an exception MyCheckedIntException for you. 将为您抛出异常MyCheckedIntException



The Expansion, for Cleaner Look 扩展,为更清洁的外观

If you want to use it like any of these: 如果您想像以下任何一样使用它:

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

Then simply add overloading to the operator overloads : 然后只需将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
}

You can do likewise for all other operators. 您可以为所有其他运营商做同样的事情。

You can not check if the result of that sum overflows the range, or not, because if you have only the result, you don't have all required data. 您无法检查该总和的结果是否超出范围,因为如果您只有结果,则您没有所有必需的数据。 If your problem is really with overflowing int , you have several options: 如果你的问题真的是溢出int ,你有几个选择:

  1. You can create your own class for list, like @tenbits suggests. 您可以为列表创建自己的类,如@tenbits建议的那样。
  2. You can create extension method for your list. 您可以为列表创建扩展方法。
    2a) Create the same Add method as in option 1. 2a)创建与选项1中相同的Add方法。
    2b) Create method, which adds numbers in it and decides (you have to know what operation you want to do with those numbers, but there shouldn't be any issues with changing ints into longs and so on): 2b)创建方法,在其中添加数字并决定(你必须知道你想对这些数字做什么操作,但是将整数改成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); } } 

I think that you can create some other examples, but without big difference. 我认为你可以创建一些其他的例子,但没有太大的区别。

However it is important to note here, that (from what I tried) using the checked keyword was always the fastest solution. 然而,重要的是要注意,使用checked关键字(从我尝试过)始终是最快的解决方案。 In fact it was almost as fast as the simple insert without check, so if there are no serious reasons why not to use the checked keyword, I have to recommend it. 实际上它几乎和没有检查的简单插入一样快,所以如果没有严重的理由为什么不使用checked关键字,我必须推荐它。

Before adding, I would ( ref ) : 在添加之前,我会( 参考 ):

Int.TryParse(string, int) Int.TryParse(string,int)

Thus if it fails due to being > int.MaxValue or < Int.MinValue, it will return false, thus you can process this accordingly. 因此,如果由于> int.MaxValue或<Int.MinValue而失败,它将返回false,因此您可以相应地处理它。

Hope this helps 希望这可以帮助

Simply you can do it with parse and casting the value to a larger type like long: 简单地说,你可以通过解析并将值转换为更长的类型来实现:

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

it will throw System.OverflowException. 它将抛出System.OverflowException。

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

otherwise will add the integer value. 否则将添加整数值。

There is one thing to consider. 有一点需要考虑。 What is you actual intention here? 你在这里的实际意图是什么? I mean: if you don't want to add results that cause overflow, why do you check them when you are actually trying to add them to the list? 我的意思是:如果您不想添加导致溢出的结果,为什么在实际尝试将它们添加到列表时检查它们? What do you do with the results that cause overflow? 你怎么处理导致溢出的结果? Do you add them to some other list? 你把它们添加到其他列表中吗? Or do you ignore them? 或者你不理睬他们?

What I would do, is to check for the overflow before you actually call List.Add() . 我要做的是在你实际调用List.Add()之前检查溢出。 This way, you have more control over the flow of your data. 这样,您就可以更好地控制数据流。 You can ignore, log, replace etc. your overflown data. 您可以忽略,记录,替换等溢出的数据。

Just some things to consider. 只是要考虑的一些事情。

2 ways to handle it: 2种处理方式:

  1. Wrap your code with checked/unchecked (as you are doing now) 使用checked/unchecked包裹您的代码(正如您现在所做的那样)
  2. Use the /checked compiler option (which is turned off by default). 使用/ checked编译器选项(默认情况下关闭)。

Here is my question Is there any alternative for this? 这是我的问题这有什么替代方案吗? Can I define a list of checked integers? 我可以定义已检查整数的列表吗? How can I make a list that throws an exception in the case where the value added to the list exceeds the limit? 如何在列表中添加的值超出限制的情况下创建引发异常的列表?

The overflow happens in the calculation before it is passed to the List, so it is impossible for a List class to detect such overflow. 在将计算传递给List之前计算中发生溢出,因此List类不可能检测到此类溢出。 The word overflow is used in its strictest sense here. 溢出这个词在这里用得最严格。

The alternative is based on what you already know, ie using a checked context. 替代方案基于您已经知道的内容,即使用已checked上下文。 You can use the compilation option /checked , which might relieve you from using the keyword. 您可以使用编译选项/选中 ,这可以减轻您使用关键字的麻烦。 Note the calling code (not the List code) needs to be compiled with this option. 请注意,需要使用此选项编译调用代码(而不是List代码)。

The short answer is: No you can't. 简短的回答是:不,你不能。

There are other "workarounds" that doesn't do exactly what you wanted in the other answers, but here is the basic explanation for why you can't do what you wanted: 还有其他“解决方法”在其他答案中没有完全符合您的要求,但这里有基本解释为什么您不能做您想要的事情:

Your code basically breaks down to something like this when you compile it: 编译时,代码基本上会分解为这样的代码:

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

The compiler is simply helping you save keystrokes by not forcing you to create named temporary variables for every sub-expression. 编译器只是帮助您保存击键,而不是强制您为每个子表达式创建命名临时变量。 Because those temporary variables must be created. 因为必须创建那些临时变量。

To understand why x + 1 must be calculated before the Add(...) method is called you need to understand how a CPU executes code, some basic assembly and some concepts of compilation. 要理解为什么必须在调用Add(...)方法之前计算x + 1您需要了解CPU如何执行代码,一些基本程序集和一些编译概念。 All of that stuff is beyond the scope of this question - ask a new question if you want to know more about it. 所有这些都超出了这个问题的范围 - 如果你想了解更多关于它的问题,可以提出一个新问题。

Try to introduce IntWrapper class, which takes responsibility of adding two ints. 尝试介绍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;
  }
}

Use Add method to add two integer. 使用Add方法添加两个整数。

You need to detect overflow in the result of your calculation before you store in the list. 在存储到列表中之前,需要检测计算结果中的溢出。

assuming x and y are positive: 假设x和y是正数:

if (x + y) < x then overflow if(x + y)<x然后溢出

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM