在某些特定情况下,用作控制流机制的异常是否有效?

InB*_*een 6 .net c# exception-handling

我正在调整实现中的一些代码RationalNumber.特别是在平等逻辑中,我正在考虑以下内容:

public bool Equals(RationalNumber other)
{
   if (RationalNumber.IsInfinity(this) ||
       RationalNumber.IsInfinity(other) ||
       RationalNumber.IsNaN(this) ||
       RationalNumber.IsNaN(other))
   {
       return false;
   }

   try
   {
       checked
       {
           return this.numerator * other.Denominator == this.Denominator * other.numerator;
       }
   }
   catch (OverflowException)
   {
       var thisReduced = RationalNumber.GetReducedForm(this);
       var otherReduced = RationalNumber.GetReducedForm(other);
       return (thisReduced.numerator == otherReduced.numerator) && (thisReduced.Denominator == otherReduced.Denominator);
   }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我正在使用异常作为流量控制机制.这背后的原因是我不想在每次平等检查中评估两个分数的最大公约数的惩罚.因此,我只决定在最不可能的情况下这样做:一个或两个交叉产品溢出.

这是可接受的做法吗?我总是读到异常永远不应该被用作代码的流机制,但我真的没有看到另一种方法来实现我想要的东西.

欢迎任何替代方法.

Ham*_*jam 1

通常捕获异常的开销很高,如果您可以对异常采取一些措施,则应该捕获异常。

对于你的情况,你可以对异常做一些事情。在我看来,将其用作控制流不是问题,但我建议您实现逻辑(检查不同的条件以防止异常),然后对两个选项进行基准测试并比较性能,因为通常捕获异常具有很高的开销,但如果检查是为了防止异常需要更多时间,然后处理异常是更好的方法。

由于OP评论而更新(它是一个新的实现,我们没有使用.NET框架的Rational。分子和分母的类型是long

您可以使用更大的类型来防止溢出异常,例如BigIntegerdecimalBigInteger

decimal thisNumerator = this.numerator;
decimal thisDenominator = this.numerator;
decimal otherNumerator = other.numerator;
decimal otherDenominator = other.numerator;

checked
{
    return thisNumerator * otherDenominator == thisDenominator * otherNumerator;
}
Run Code Online (Sandbox Code Playgroud)

根据评论更新:

一个显示异常开销的简单示例。

const int Iterations = 100000;
var sw = new Stopwatch();
var sum1 = 0;
sw.Start();
for (int i = 0; i < Iterations; i++)
{
    try
    {
        var s = int.Parse("s" + i);
        sum1 += s;
    }
    catch (Exception)
    {
    }
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Console.WriteLine(sum1);

var sw2 = new Stopwatch();
var sum2 = 0;
sw2.Start();
for (int i = 0; i < Iterations; i++)
{
    try
    {
        int s;
        if (int.TryParse("s" + i, out s))
            sum2 += s;
    }
    catch (Exception)
    {
    }
}
sw2.Stop();
Console.WriteLine(sw2.ElapsedMilliseconds);
Console.WriteLine(sum2);
Run Code Online (Sandbox Code Playgroud)

结果是:处理异常至少慢 170 倍

5123
0
30
0

  • 感谢您的反对票。您能否解释一下原因,以便我改进答案并使社区变得更美好? (3认同)