C#,多个 == 运算符重载,没有模棱两可的空值检查
Posted
技术标签:
【中文标题】C#,多个 == 运算符重载,没有模棱两可的空值检查【英文标题】:C#, multiple == operator overloads without ambiguous null check 【发布时间】:2017-07-10 22:28:39 【问题描述】:简介: 我有几个类做同样的工作,但具有不同的值类型(例如浮点数或整数的向量)。 现在我希望能够检查相等性,这种相等性也应该在类型之间起作用(例如 vectorF == vectorI)。 此外,应该可以进行空检查(vectorF == null)。
方法: 我的方法是为 == 和 != 运算符创建多个重载,每个可能的组合一个。
public sealed class VectorF
[...]
public static bool operator == (VectorF left, VectorI right)
// Implementation...
public static bool operator == (VectorF left, VectorF right)
// Implementation...
// Same for != operator
[...]
问题: 使用多个重载,我不能只使用 == 运算符进行空检查,因为调用会模棱两可。
var v = new VectorF([...]);
if (v == null) // This call is ambiguous
[...]
我知道可以使用 ReferenceEquals 或 null 强制转换,但这种方法对我来说是一个严重的限制。
var v = new VectorF([...]);
if(object.ReferenceEquals(v, null)) // Would work, is not user friendly.
[...]
if(v == (VectorF)null) // Would also work, is neither user friendly.
[...]
问题: 有没有办法以某种方式实现 == 运算符,它允许简单的空值检查,并允许不同向量之间的相等性检查?
或者,我可以/应该如何实现这一点?
【问题讨论】:
看起来你的 Vector 类应该是不可变的结构。那么null
的问题就不会出现。 (我假设您的类只包含 2 或 3 个值。)
听起来像zugzwang:要么好看==
要么== null
。如何有方法与其他类型的向量进行比较?例如。 VectorF.IsSame(VectorI)
?编译器在尝试vectorF == vectorI
时会显示用户错误,然后用户将搜索方法进行比较,tada,问题解决了吗?另一件事:比较float
和int
并不精确,如何先将VectorF
转换为VectorI
,然后比较两个VectorI
?
为什么你需要左右重载..你能分享我们重载方法的内容吗..
我认为添加从 VectorI 到 VectorF 的隐式转换可以简化很多问题
@levent:我只是习惯于调用左右变量,我已经从其他重载中采用了这个,其中顺序可能很重要(例如矩阵乘法)。
【参考方案1】:
我会从一开始就推迟整个设计。我永远不会使用不同类型之间的值语义来实现 ==
,我会觉得它相当混乱:instaceTypedA == instanceTypedB
大喊引用相等(至少对我而言)。
如果您需要此功能,请在 VectorI
和 VectorF
之间实现隐式转换。这就是框架的工作方式。当您执行以下操作时:
int i = 1;
double d = 1;
var b = i == d;
超载==(int, double)
不会神奇地产生。发生的情况是i
被隐式转换为double
并调用==(double, double)
。
【讨论】:
谢谢。你是对的,== 应该是引用相等。我没有想到隐式转换,因为我希望调用尽可能优化。但是,由于无论如何都会转换值,所以它毕竟没有太大区别。【参考方案2】:您可以通过使用is
来反转比较:
if (v is VectorF)
如果v
是null
,此检查将失败。
【讨论】:
我不太喜欢这个解决方案。你真正在做的事情的语义隐藏在一个“聪明”的把戏中;阅读此代码,说实话,您是否正在检查null
远不清楚。
嗯,使用is
(或as
)进行类型检查是很常见的,尽管不是每个人都知道它也会进行空值检查。一旦你知道很明显null
不是特定类型。
对 object.ReferenceEquals 的改进是什么,除了更短的代码?我会假设 is 对空值检查有相当大的性能开销。
我猜差别不大,但你可以测试一下。【参考方案3】:
在这种情况下,我会做的是不要重载 ==
运算符,而是执行以下操作:
public static bool operator == (VectorF left, object right)
if (object.ReferenceEquals(null, right))
// handle null case
VectorF rightF = right as VectorF;
if (!object.ReferenceEquals(null, rightF))
// Compare VectorF
VectorI rightI = right as VectorI;
if (!object.ReferenceEquals(null, rightI))
// Compare VectorI
// and so on...
【讨论】:
Ewww,牺牲编译时类型安全来节省重复空检查?以上是关于C#,多个 == 运算符重载,没有模棱两可的空值检查的主要内容,如果未能解决你的问题,请参考以下文章