dotnet 中的判等

简介: dotnet 中的判等

前言

前几天,同事在 .net 程序中,遇到一个很 “诡异” 的问题:明明两个值是相等的,可偏偏却不相等,这是怎么回事呢?

初遇问题

刚听到这个问题时,我是满脸的不相信,怎么可能?但是亲自调试一看,确实什么都相等,但确实返回的不相等。见鬼了?为了更近一步研究这个问题,我特意模仿原程序逻辑写了一个简单的测试程序。

示例代码

using System.Collections.Generic;
using System.Linq;

namespace TestOperatorEqualEqual
{
   
   
    class CClassTest
    {
   
   
        public int data1;
        public int data2;
    }

    class Program
    {
   
   
        public static bool IsClassTestEqual(CClassTest lhs, CClassTest rhs)
        {
   
   
            return lhs == rhs;
        }

        static void Main(string[] args)
        {
   
   
            List<CClassTest> testList = new List<CClassTest>();
            for (int idx = 0; idx < 100; ++idx)
            {
   
   
                testList.Add(new CClassTest {
   
    data1 = idx, data2 = idx+1 });
            }

            CClassTest target = new CClassTest{
   
   data1 = 50, data2 = 51 };
            var bContained = testList.Any(item => {
   
    return IsClassTestEqual(item, target); });
            System.Console.WriteLine(bContained ? "yes" : "no");
            System.Console.ReadKey();
        }
    }
}

明明存在相等项(data1== 50, data2 == 51),但是 Any 却返回了 false。是不是很诡异?你能一眼看出上面程序的问题吗?

单纯从 vs 中看源码,通过调试查看,都看不出任何问题。怎么办?一般从源码看不出问题,就需要从更底层来看,对于 C++ 编写的原生程序来说就是查看汇编代码,对于 C# 编写的程序,优先查看 IL(Intermediate Language) 代码。微软提供了查看 IL 代码的工具—— ildasm

ildasm

可以使用 everything 在磁盘上搜索 ildasm 的位置。

search-ildasm-result.png

ildasm 界面中,通过 file -> open 打开需要查看的程序,然后找到需要查看的方法,如下图:

view-ildasm.png

好家伙,直接调用了 ceq,看到这段 IL 代码,我恍然大明白,原来是比较了两个变量的地址!难怪即使两个类的成员一模一样,但是总返回 false 了!

赶紧谷歌一下 .net operator== msdn,发现了官方说明,链接如下:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators。读完发现自己读书太少了!下图截取自上面的官方文档。

reference-type-equality-msdn.png

原来,== 对于引用类型来说(class),是比较两个变量是否引用同一个对象,而不是比较两个变量的成员是否相等。

修复

知道问题的本质原因,修改起来就很简单了。只需要按成员比较两个 CClassTest 实例的成员是否相等即可。

关键函数修改如下:

public static bool IsClassTestEqual(CClassTest lhs, CClassTest rhs)
{
   
   
    return lhs.data1 == rhs.data1 && lhs.data2 == rhs.data2;
}

彩蛋

既然文档里说了可以重载 == operator,那么就重载一下呗。这样就不用额外提供一个比较函数了,直接使用 rhs == rhs 这种形式的比较就可以了。于是我大笔一挥,写下了如下代码:

class CClassTest
{
   
   
    public int data1;
    public int data2;

    public static bool operator == (CClassTest lhs, CClassTest rhs)
    {
   
   
        if (lhs == null && rhs == null)
        {
   
   
            return true;
        }
        else if (lhs != null && rhs != null)
        {
   
   
            return lhs.data1 == rhs.data1 && lhs.data2 == rhs.data2;
        }
        else
        {
   
   
            return false;
        }
    }

    public static bool operator != (CClassTest lhs, CClassTest rhs)
    {
   
   
        return !(lhs == rhs);
    }
}

你能看出上面代码的问题吗?

对,上面的写法会导致 stackoverflow

stackoverflow.png

那正确的写法是什么样的呢?

正确的写法如下:

public static bool operator ==(CClassTest lhs, CClassTest rhs)
{
   
   
    if ((object)lhs == null && (object)rhs == null)
    {
   
   
        return true;
    }
    else if ((object)lhs != null && (object)rhs != null)
    {
   
   
        return lhs.data1 == rhs.data1 && lhs.data2 == rhs.data2;
    }
    else
    {
   
   
        return false;
    }
}

说明:高版本的 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

总结

  • 每种语言都有自己独特的规则,学习并适应,才能更好的使用它。

  • 多读书!

相关文章
|
数据可视化 算法 数据挖掘
基于python的笔记本电脑购买意愿影响因素分析,包括情感分析和聚类分析
本文通过Python大数据技术对笔记本电脑评论数据进行情感分析和聚类分析,揭示了产品性能、外观设计和用户地区等因素对购买意愿的重要影响,并为企业提供了优化产品设计和销售策略的参考。
495 2
|
13天前
|
人工智能 搜索推荐 物联网
告别深夜批改:用Qwen3-VL大模型打造会“理解”的作文阅卷助手
基于Qwen3-VL打造作文阅卷助手,通过对300篇高中作文进行LoRA微调,将教师从繁重批改中解放,更通过即时、客观的反馈助力学生写作能力提升,展现了垂直领域大模型应用的实用价值与高效落地路径。
141 2
|
14天前
|
存储 人工智能 自然语言处理
告别“抽卡式”创作,集之互动定义商业级AIGC视频交付新标准
集之互动推出品牌级AI视频解决方案,以自研“无垠大模型”实现高可控、强贴合、高安全的广告内容生成。通过精准控制、品牌理解、私有化部署与全栈赋能,推动AIGC从技术玩具迈向工业化营销落地,助力企业构建自主、高效、合规的智能内容生产力。
120 1
|
18天前
|
存储 人工智能 数据可视化
最新版:阿里云万小智 AI 建站服务配置与价格说明
阿里云万小智 AI 建站是基于通义大模型开发的一站式建站服务,集成云服务器、存储、CDN 等基础资源,无需专业开发知识即可完成网站搭建。本文详细梳理其不同版本的功能配置、资源规格及收费标准,为用户选择合适的建站方案提供参考。
|
8月前
|
JSON 算法 API
一文掌握 1688 商品详情 API 接口:从入门到实战
1688是国内领先的综合电商批发平台,提供海量商品资源。其商品详情API助力开发者与企业获取商品的详细信息(如属性、价格、库存等),广泛应用于电商数据分析、比价系统及采购场景。API支持GET/POST请求,需传入通用参数(app_key、timestamp等)与业务参数(如product_id)。返回JSON格式数据,包含商品标题、价格、图片链接等详情,提升业务效率与决策精准度。
|
10月前
|
存储 机器学习/深度学习 人工智能
AllData数据中台核心菜单十二:数据同步平台
杭州奥零数据科技有限公司成立于2023年,专注于数据中台业务,维护开源项目AllData并提供商业版解决方案。AllData提供数据集成、存储、开发、治理及BI展示等一站式服务,支持AI大模型应用,助力企业高效利用数据价值。
AllData数据中台核心菜单十二:数据同步平台
快手自动抢红包辅助插件,快手抢红包福袋脚本全自动,智能抢包软件按键版
这是一套快手自动抢红包插件源码,通过模拟点击实现自动化操作。例如准备100个快手账号配合此插件挂机抢红包
|
容器
C++17新特性之try_emplace与insert_or_assign
由于std::map中,元素的key是唯一的,我们经常遇到这样的场景,向map中插入元素时,先检测map指定的key是否存在,不存在时才做插入操作,如果存在,直接取出来使用,或者key不存在时,做插入操作,存在时做更新操作。
355 0
|
10月前
|
人工智能 安全 搜索推荐
基于函数计算一键部署 AI 陪练,快速打造你的专属口语对练伙伴
基于函数计算一键部署 AI 陪练,快速打造你的专属口语对练伙伴
|
消息中间件 存储 Java
分享一下rocketmq入门小知识
分享一下rocketmq入门小知识
364 0
分享一下rocketmq入门小知识

热门文章

最新文章