我有很多计算,特别是乘法,其中第一部分有时为零,在这种情况下我不想评估第二个操作数。C# 中至少有两个短路运算符:它们仅在必要时评估第二个操作数&&
。||
我想用乘法运算符实现类似的行为。
在.net中,您不能&&
直接重载运算符,但可以重载&
和false
运算符,因此您可以使用扩展点来更改短路运算符的行为。您可以在这篇文章中找到更多详细信息C# 运算符重载:'&&' 运算符
有没有办法为乘法运算符实现这种或类似的行为?
这是一个纯语法问题,因为实现非常简单。下一个方法在功能方面完全实现了我想要的:
public static double ShortCircuitMultiply(double val, Func<double> anotherValue)
{
var epsilon = 0.00000001;
return Math.Abs(val) < epsilon ? 0 : val * anotherValue();
}
注意:这个实现并不完整:在C#0.0
中,
如果你乘以Double.NaN
orDouble.NegativeInfinity
或Double.PositiveInfinity
,你会得到NaN
,但就ShortCircuitMultiply
- 而言只有零。让我们忽略这个细节,它在我的领域真的无关紧要。
因此,现在如果我将其称为ShortCircuitMultiply(0.0, longOperation)
where longOperation
is Func<double>
,则不会评估最后一个术语,并且操作的结果实际上将为零。
问题是,正如我已经说过的,我会接到很多ShortCircuitMultiply
电话,我想让代码更具可读性。0.0 * longOperation()
如果可能的话,我希望代码类似于。
另一个注意事项:我尝试在其上构建包装器double
并创建隐式强制转换为双重和重载*
运算符。我明白,这可能是多余的:我想实现可读性,但试图构建另一个 wrapper。无论如何,下一个代码展示了我的意图:
class MyDouble
{
double value;
public MyDouble(double value)
{
this.value = value;
}
public static MyDouble operator *(MyDouble left, MyDouble right)
{
Console.WriteLine ("* operator call");
return new MyDouble(left.value * right.value);
}
public static implicit operator double(MyDouble myDouble)
{
Console.WriteLine ("cast to double");
return myDouble.value;
}
public static implicit operator MyDouble(double value)
{
Console.WriteLine ("cast to MyDouble");
return new MyDouble(value);
}
}
现在,如果我选择:
MyDouble zero = 0;
Console.WriteLine (zero * longOperation()); //longOperation is still Func<double>
我收到:
cast to MyDouble
called longOperation <-- want to avoid this (it's printed from longOperation body)
cast to double
cast to MyDouble
* operator call
cast to double
0
但是正如您所看到的,longOperation
在调用重载运算符之前很久就对其进行了评估,并且我不能用Func
or替换其中一个参数Expression
以使其变得懒惰。