当比较两个数字/函数的最小值或最大值时,如果第一个的情况是真的,那么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())
为了短路,但我认为没有重写就比较清楚了。这是短路吗?
答案 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.Min
或Math.Max
是两个普通的静态方法调用,编译器不会在这个意义上进行优化。
代码的评估顺序为:z(),Math.Max,x&gt; ...
如果您确实想确定,请查看IL代码。