【问题标题】:Determine if a checked operation using Func on integers resulted in an overflow or underflow?确定对整数使用 Func 的检查操作是否导致上溢或下溢?
【发布时间】:2015-11-18 04:44:35
【问题描述】:

我很难确定使用Func<int, int>int 进行的checked 操作是否会导致上溢或下溢。如果我不使用Func<int, int>,我已经找到了一种方法来确定这一点

int _Data = Data; // Data is some integer value
int scaleValue = int.MaxValue; // Just for completion, could be any value
try 
{ 
    checked 
    { 
        Data *= scaleValue; 
    } 
}
catch (System.OverflowException ex)
{
    // Cast the values to float so we can operate beyond the integer range
    // This way we can check if we went over Max or Min Values
    if ((float)_Data * (float)scaleValue > int.MaxValue)
        Data = int.MaxValue;
    else
        Data = int.MinValue;
}

虽然如果我确实使用Func<int, int>,那么我无法使用上面的技巧来确定结果。

int _Data = Data;
Func<int, int> scaleFunction = (x) => (x * int.MaxValue);
try 
{ 
    checked 
    { 
        Data = scaleFunction(Data); 
    } 
}
catch (System.OverflowException ex)
{
    // How to tell if scaleFunction created under or over flow?
    if ((float)_Data * (float)scaleValue > int.MaxValue)
        Data = int.MaxValue;
    else
        Data = int.MinValue;
}

我看到的唯一选择是“改变”给定的Func&lt;int, int&gt; 以在float 上工作,但如果事先不知道Func&lt;int, int&gt; 的结构,那么我认为它不能改变。

谁能看到一个偷偷摸摸的方法来完成这个?

这是我发现原始偷偷摸摸操作的线程:Determine if integer overflow is over or under bounds

这是我之前提出的一个相关问题,提供了更多背景信息:Determine if operation will result in overflow?

编辑:在我使用此代码时,我无法控制 Func&lt;int, int&gt; 的创建方式。因此,我不能在其中放置 check 表达式或将其阻塞。

我也没有意识到check 不会检查其中使用的溢出“内部函数”。如果是这样,我认为这个问题要困难得多。由于无法将Func 修改为使用check,我们必须手动进行检查。

手工操作的问题是它(目前对我来说)似乎不可能。使用检查原始值是否与Func 的输出值具有相同符号的技巧可能是有意义的。问题是您无法判断 Func 是否非法将值增加到超过最大值,或者是否合法地将值减小到 0 以下;反之亦然。

【问题讨论】:

  • 你应该把 check 放在 lambda 里面。像这样x =&gt; { checked { return x*int.MaxValue; } };你能改变功能吗?
  • @M.kazemAkhgary 你甚至可以通过使用checked 表达式而不是checked 块来编写更简单的代码:x =&gt; checked(x * int.MaxValue)
  • 同样,当对 int 的操作不溢出时,并不意味着它下溢。尽管在这两种情况下运行时都会引发溢出异常。但是您可以假设当结果小于int.MinValue 时,它会下溢。你也必须检查下溢。而不是else .... 你应该这样做else if ((double)_Data * (double)scaleValue &lt; int.MinValue) ....
  • @M.kazemAkhgary 所以check 块只会在操作溢出时抛出OverflowException 而不会为下溢抛出一个?
  • 在测试后似乎在任何一种情况下都会抛出OverflowException。因此,如果已检查的块引发异常,则只有两种情况超出或不足。检查一个案例,发现它是假的,一定意味着另一个案例是真的。

标签: c#


【解决方案1】:

在我使用此代码时,我无法控制 Func 的创建方式。因此,我不能在其中放置检查表达式或阻塞。

那么,你输了。

checked/unchecked 是任何单个算术指令在 IL 级别的属性。它不会跨方法调用流动。这不是您可以打开或关闭的设置。它为每条指令单独编译成 .NET 二进制文件。

任何一段代码的作者决定了checked 属性,并且不能更改。

事实上,如果您可以访问其他人的代码并巧妙地改变基本算术指令的行为,那将是危险且不可靠的。

【讨论】:

    【解决方案2】:

    checked 块或表达式(两种风格都存在并具有相同的效果)不会被调用的方法“继承”,因此您的 lambda 实际上是在未经检查的上下文中相乘。

    请尝试以下方法:

    int _Data = Data;
    Func<int, int> scaleFunction = (x) => checked(x * int.MaxValue);
    try 
    { 
        Data = scaleFunction(Data); 
    } 
    catch (System.OverflowException ex)
    {
        // handle overflow...
    }
    

    【讨论】:

    • 问题是在代码中的那个时候我不会是创建函数的人。我最终必须接受给我的任何Func&lt;int, int&gt;,因此确保此类的使用不会超过/低于我的Data
    • @KDecker 在这种情况下,usr 的答案是唯一正确的答案。毫无例外地溢出是许多计算的有意部分,因此它在运行时无法从外部控制。请注意,C# 允许在 Build -> Advanced 下的项目设置中指定默认(编译时)溢出行为。当然,实现者仍然可以使用unchecked 块或表达式来覆盖该行为。
    猜你喜欢
    • 1970-01-01
    • 2018-02-28
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多