How can i define a List of checked integers

本秂侑毒 提交于 2019-12-07 14:23:08

问题


I have a List of Integers defined as List<int> myIntList = new List<int>(); As usual I will add value to the list using myIntList.Add() method. 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. I need to throw an exception here. I know myIntList.Add(checked(x + 1)); will do the job perfectly or I can even enclose the myIntList.Add() within checked{} like the following:

 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.


回答1:


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? Is it not overflowed, but returns long, for example?

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



回答2:


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.



Implementation

The struct

The CheckedInt struct would be something like this:

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.



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.



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:

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.




回答3:


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:

  1. You can create your own class for list, like @tenbits suggests.
  2. You can create extension method for your list.
    2a) Create the same Add method as in option 1.
    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):

    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. 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.




回答4:


Before adding, I would (ref) :

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.

Hope this helps




回答5:


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.

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

otherwise will add the integer value.




回答6:


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(). 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.




回答7:


2 ways to handle it:

  1. Wrap your code with checked/unchecked (as you are doing now)
  2. Use the /checked compiler option (which is turned off by default).



回答8:


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. The word overflow is used in its strictest sense here.

The alternative is based on what you already know, i.e. using a checked context. 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.




回答9:


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. All of that stuff is beyond the scope of this question - ask a new question if you want to know more about it.




回答10:


Try to introduce IntWrapper class, which takes responsibility of adding two ints.

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.




回答11:


You need to detect overflow in the result of your calculation before you store in the list.

assuming x and y are positive:

if (x + y) < x then overflow



来源:https://stackoverflow.com/questions/34745422/how-can-i-define-a-list-of-checked-integers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!