前言
前几天,同事在 .net
程序中,遇到一个很 “诡异” 的问题:明明两个值是相等的,可偏偏却不相等,这是怎么回事呢?
初遇问题
刚听到这个问题时,我是满脸的不相信,怎么可能?但是亲自调试一看,确实什么都相等,但确实返回的不相等。见鬼了?为了更近一步研究这个问题,我特意模仿原程序逻辑写了一个简单的测试程序。
示例代码
1 | using System.Collections.Generic; |
明明存在相等项(data1== 50, data2 == 51
),但是 Any
却返回了 false
。是不是很诡异?你能一眼看出上面程序的问题吗?
单纯从 vs
中看源码,通过调试查看,都看不出任何问题。怎么办?一般从源码看不出问题,就需要从更底层来看,对于 C++
编写的原生程序来说就是查看汇编代码,对于 C#
编写的程序,优先查看 IL(Intermediate Language)
代码。微软提供了查看 IL
代码的工具—— ildasm
。
ildasm
可以使用 everything
在磁盘上搜索 ildasm
的位置。
在 ildasm
界面中,通过 file -> open
打开需要查看的程序,然后找到需要查看的方法,如下图:
好家伙,直接调用了 ceq
,看到这段 IL
代码,我恍然大明白,原来是比较了两个变量的地址!难怪即使两个类的成员一模一样,但是总返回 false
了!
赶紧谷歌一下 .net operator== msdn
,发现了官方说明,链接如下:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators。读完发现自己读书太少了!下图截取自上面的官方文档。
原来,==
对于引用类型来说(class
),是比较两个变量是否引用同一个对象,而不是比较两个变量的成员是否相等。
修复
知道问题的本质原因,修改起来就很简单了。只需要按成员比较两个 CClassTest
实例的成员是否相等即可。
关键函数修改如下:
1 | public static bool IsClassTestEqual(CClassTest lhs, CClassTest rhs) |
彩蛋
既然文档里说了可以重载 == operator
,那么就重载一下呗。这样就不用额外提供一个比较函数了,直接使用 rhs == rhs
这种形式的比较就可以了。于是我大笔一挥,写下了如下代码:
1 | class CClassTest |
你能看出上面代码的问题吗?
对,上面的写法会导致 stackoverflow
!
那正确的写法是什么样的呢?
正确的写法如下:
1 | public static bool operator ==(CClassTest lhs, CClassTest rhs) |
说明:高版本的
c#
(应该是c# 7
开始支持的) 还支持使用is
判断一个变量是否为空。下面这种写法更优雅!
if (lhs is null && rhs is null) ...
源码下载
csdn: https://download.csdn.net/download/xiaoyanilw/18335150
百度云盘链接: https://pan.baidu.com/s/1VmnqoflrbWXFjeQV7TrKTg 提取码: dsqt
总结
每种语言都有自己独特的规则,学习并适应,才能更好的使用它。
多读书!