是否与Math.Min或Math.Max短路相比?

时间:2012-01-18 19:08:43

标签: c# short-circuiting

当比较两个数字/函数的最小值或最大值时,如果第一个的情况是真的,那么C#会短路并且第二个意味着真实吗?这些案例的具体例子是

if(x < Math.Max(y, z()))

if(x > Math.Min(y, z()))

由于Math.Max(y, z())将返回一个至少与y一样大的值,如果x&lt;那么就没有必要评估z(),这可能需要一段时间。与Math.Min类似的情况。

我意识到这些都可以按照

的方式重写
if(x < y || x < z())

为了短路,但我认为没有重写就比较清楚了。这是短路吗?

5 个答案:

答案 0 :(得分:18)

正如其他人所指出的那样,编译器对Min或Max的语义一无所知会允许它在调用方法之前打破参数被评估的规则。

如果你想自己编写,你可以很容易地做到:

static bool LazyLessThan(int x, int y, Func<int> z)
{
    return x < y || x < z();
}

然后调用它

if (LazyLessThan(x, y, z))

if (LazyLessThan(x, y, ()=>z()))

或者就此而言:

static bool LazyRelation<T>(T x, T y, Func<T> z, Func<T, T, bool> relation)
{
    return relation(x, y) || relation(x, z());
}
...
if (LazyRelation(x, y, ()=>z, (a,b)=> a < b))) 

答案 1 :(得分:10)

不,它不会短路,并且将始终评估z()。如果你想要短路行为,你应该像你所做的那样重写。

答案 2 :(得分:5)

Math.Min()Math.Max()就像其他方法一样。必须对它们进行求值,以便返回将用作比较中第二个参数的值。如果您想要短路,那么您必须使用||运算符来编写条件,如您所示。

答案 3 :(得分:3)

(没有什么特别新的补充,但我想我会分享我在其上运行的测试结果。)

可以通过CLR的即时编译器轻松地内联Math.Max(),并且从那里我很好奇它是否可能以短路方式进一步优化代码。

所以我掀起了一个微基准测试,每个测试两个表达式1,000,000次。 对于z(),我使用了一个使用递归方法计算Fib(15)的函数。以下是运行两者的结果:

x < Math.Max(y, z()) :   8097 ms
x < y || x < z()     :     29 ms

我猜测CLR不会以任何阻止方法调用执行的方式转换代码,因为它不知道(并且不检查是否)该例程有任何副作用。

答案 4 :(得分:2)

不,它不会短路,至少在C#编译器级别。 Math.MinMath.Max是两个普通的静态方法调用,编译器不会在这个意义上进行优化。

代码的评估顺序为:z(),Math.Max,x&gt; ...

如果您确实想确定,请查看IL代码。