我如何定义一个检查整数列表
How can i define a List of checked integers
我有一个整数列表,定义为 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);
}
这是我的问题有什么替代方案吗?我可以定义一个检查整数列表吗?如何做一个列表,如果添加到列表的值超过限制,就会抛出异常?
更新:
谢谢大家的回复,你们中的大多数人建议在将它们添加到列表之前检查整数(如果超出边界则抛出异常)。这与我通过给定代码段所做的相同 checked{// add elements }
它会在没有任何复杂条件检查的情况下抛出异常。
在存储到列表中之前,您需要检测计算结果是否溢出。
假设 x 和 y 为正:
如果 (x + y) < x 则溢出
尝试引入IntWrapper
class,它负责将两个整数相加。
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
方法将两个整数相加。
你在错误的层次上解决问题。首先,您的计算 - 它 returns 某种类型的值 - int
、long
等。不应该检查溢出吗?不是溢出了,而是returnslong
,比如
如果在添加到容器时仍然需要这样做,您可以像这样创建检查列表:
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);
}
}
您无法检查该总和的结果是否超出范围,因为如果您只有结果,则没有所有需要的数据。如果您的问题确实是 int
溢出,您有多种选择:
- 您可以创建自己的 class 列表,就像@tenbits 建议的那样。
您可以为列表创建扩展方法。
2a) 创建与选项 1 中相同的 Add
方法。
2b) 创建方法,在其中添加数字并决定(你必须知道你想对这些数字做什么操作,但是将整数转换为长整数等等应该没有任何问题):
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
关键字,我不得不推荐它。
在添加之前,我会 (ref) :
Int.TryParse(string, int)
因此,如果由于 > int.MaxValue 或 < Int.MinValue 而失败,它将 return false,因此您可以相应地处理它。
希望对您有所帮助
基本思路
假设您想要这样的行为:
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 Whosebug
}
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 Whosebug
}
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 Whosebug
}
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 Whosebug
}
//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<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 Whosebug
}
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 Whosebug
}
您可以对所有其他运算符执行同样的操作。
简单地说,您可以通过解析并将值转换为更大的类型来完成此操作,例如 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()));
否则将添加整数值。
需要考虑一件事。你在这里的实际意图是什么?我的意思是:如果您不想添加导致溢出的结果,那么为什么在实际尝试将它们添加到列表时检查它们?你如何处理导致溢出的结果?您是否将它们添加到其他列表中?还是忽略它们?
我会做的是在您实际调用 List.Add()
之前检查溢出。这样,您就可以更好地控制数据流。您可以忽略、记录、替换等溢出的数据。
只是一些需要考虑的事情。
2种处理方式:
- 用
checked/unchecked
包装您的代码(就像您现在所做的那样)
- 使用 /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?
溢出发生在传递给List之前的计算中,所以Listclass不可能检测到这种溢出。此处使用的是最严格意义上的溢出一词。
备选方案基于您已知的知识,即使用 checked
上下文。您可以使用编译选项 /checked,这可能会减轻您使用关键字的负担。请注意调用代码(不是 List
代码)需要使用此选项进行编译。
简短的回答是:不,你不能。
在其他答案中还有其他 "workarounds" 不完全符合您的要求,但这里是对为什么您不能按照您的要求做的基本解释:
你的代码在编译时基本上会分解成这样:
int x = int.MaxValue;
int temp = x + 1;
list.Add(temp);
编译器只是通过不强制您为每个 sub-expression 创建命名的临时变量来帮助您节省击键次数。因为那些临时变量必须被创建。
要理解为什么 x + 1
必须在 之前 调用 Add(...)
方法,您需要了解 CPU 是如何执行代码的,一些基本的汇编和编译的一些概念。所有这些都超出了这个问题的范围 - 如果您想了解更多,请提出一个新问题。
我有一个整数列表,定义为 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);
}
这是我的问题有什么替代方案吗?我可以定义一个检查整数列表吗?如何做一个列表,如果添加到列表的值超过限制,就会抛出异常?
更新:
谢谢大家的回复,你们中的大多数人建议在将它们添加到列表之前检查整数(如果超出边界则抛出异常)。这与我通过给定代码段所做的相同 checked{// add elements }
它会在没有任何复杂条件检查的情况下抛出异常。
在存储到列表中之前,您需要检测计算结果是否溢出。
假设 x 和 y 为正:
如果 (x + y) < x 则溢出
尝试引入IntWrapper
class,它负责将两个整数相加。
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
方法将两个整数相加。
你在错误的层次上解决问题。首先,您的计算 - 它 returns 某种类型的值 - int
、long
等。不应该检查溢出吗?不是溢出了,而是returnslong
,比如
如果在添加到容器时仍然需要这样做,您可以像这样创建检查列表:
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);
}
}
您无法检查该总和的结果是否超出范围,因为如果您只有结果,则没有所有需要的数据。如果您的问题确实是 int
溢出,您有多种选择:
- 您可以创建自己的 class 列表,就像@tenbits 建议的那样。
您可以为列表创建扩展方法。
2a) 创建与选项 1 中相同的Add
方法。
2b) 创建方法,在其中添加数字并决定(你必须知道你想对这些数字做什么操作,但是将整数转换为长整数等等应该没有任何问题):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
关键字,我不得不推荐它。
在添加之前,我会 (ref) :
Int.TryParse(string, int)
因此,如果由于 > int.MaxValue 或 < Int.MinValue 而失败,它将 return false,因此您可以相应地处理它。
希望对您有所帮助
基本思路
假设您想要这样的行为:
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 Whosebug
}
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 Whosebug
}
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 Whosebug
}
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 Whosebug
}
//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<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 Whosebug
}
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 Whosebug
}
您可以对所有其他运算符执行同样的操作。
简单地说,您可以通过解析并将值转换为更大的类型来完成此操作,例如 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()));
否则将添加整数值。
需要考虑一件事。你在这里的实际意图是什么?我的意思是:如果您不想添加导致溢出的结果,那么为什么在实际尝试将它们添加到列表时检查它们?你如何处理导致溢出的结果?您是否将它们添加到其他列表中?还是忽略它们?
我会做的是在您实际调用 List.Add()
之前检查溢出。这样,您就可以更好地控制数据流。您可以忽略、记录、替换等溢出的数据。
只是一些需要考虑的事情。
2种处理方式:
- 用
checked/unchecked
包装您的代码(就像您现在所做的那样) - 使用 /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?
溢出发生在传递给List之前的计算中,所以Listclass不可能检测到这种溢出。此处使用的是最严格意义上的溢出一词。
备选方案基于您已知的知识,即使用 checked
上下文。您可以使用编译选项 /checked,这可能会减轻您使用关键字的负担。请注意调用代码(不是 List
代码)需要使用此选项进行编译。
简短的回答是:不,你不能。
在其他答案中还有其他 "workarounds" 不完全符合您的要求,但这里是对为什么您不能按照您的要求做的基本解释:
你的代码在编译时基本上会分解成这样:
int x = int.MaxValue;
int temp = x + 1;
list.Add(temp);
编译器只是通过不强制您为每个 sub-expression 创建命名的临时变量来帮助您节省击键次数。因为那些临时变量必须被创建。
要理解为什么 x + 1
必须在 之前 调用 Add(...)
方法,您需要了解 CPU 是如何执行代码的,一些基本的汇编和编译的一些概念。所有这些都超出了这个问题的范围 - 如果您想了解更多,请提出一个新问题。