当前位置: 首页 > news >正文

C#中判断两个 List<T> 的内容是否相等

ET实现游戏中邮件系统逻辑思路(服务端)_游戏邮件系统设计-CSDN博客

场景:今天遇到一个BUG,在服务器重启的时候(体验服),玩家之前接收的邮件又重新接收了一次,但是两封邮件的ID是不同的。ID不同说明玩家自身邮件组件向EmailManager组件拉取了两次,同时也说明EmailManager组件在玩家拉取完邮件后没清理保存,于是我先想着在接受邮件之前判断这个邮件是不是已经接收了。


修复BUG的方式很直接暴力,直接用EmailInfo与玩家自身邮件组件做对比,不过我第一时间想到的竟然是   ‘==’ ,又一次被自己气笑了。 

==运算符对于基本数据类型比较值,对于引用类型默认比较引用(内存地址)。 

由于两封邮件内容、时间、奖励等信息相同但是ID不同那只能比较除ID外的内容是否相等。


 引出正题:

1. 使用 SequenceEqual 方法

System.Linq 命名空间中的 Enumerable.SequenceEqual 方法可以用于比较两个序列的内容是否相等。

using System;
using System.Collections.Generic;
using System.Linq;class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3 };List<int> list2 = new List<int> { 1, 2, 3 };List<int> list3 = new List<int> { 1, 2, 4 };bool areEqual1 = list1.SequenceEqual(list2); // Truebool areEqual2 = list1.SequenceEqual(list3); // FalseConsole.WriteLine($"list1 and list2 are equal: {areEqual1}");Console.WriteLine($"list1 and list3 are equal: {areEqual2}");}
}

2. 使用 SetEquals 方法

如果你只关心两个集合是否包含相同的元素,而不关心顺序,可以使用 HashSet<T> 的 SetEquals 方法。

using System;
using System.Collections.Generic;class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3 };List<int> list2 = new List<int> { 3, 2, 1 };HashSet<int> set1 = new HashSet<int>(list1);HashSet<int> set2 = new HashSet<int>(list2);bool areEqual = set1.SetEquals(set2); // True,顺序不重要Console.WriteLine($"list1 and list2 contain the same elements: {areEqual}");}
}

3. 手动比较

如果你需要更复杂的比较逻辑(例如自定义对象),可以手动遍历两个列表并进行比较。

  • 属性 Value:这是一个整型属性,用于存储 MyClass 对象的值。
  • 重写 Equals 方法
    • 该方法用于比较两个 MyClass 对象是否相等。
    • 首先检查传入的对象 obj 是否是 MyClass 的实例。如果是,则比较它们的 Value 属性。
    • 如果 Value 相等,则返回 true,否则返回 false
  • 重写 GetHashCode 方法
    • 该方法返回 Value 属性的哈希码。重写这个方法是为了确保在使用哈希表等数据结构时,MyClass 对象的哈希值是基于其内容的。
using System;
using System.Collections.Generic;class MyClass
{public int Value { get; set; }public override bool Equals(object obj){if (obj is MyClass other){return this.Value == other.Value;}return false;}public override int GetHashCode(){return Value.GetHashCode();}
}class Program
{static void Main(){List<MyClass> list1 = new List<MyClass> { new MyClass { Value = 1 }, new MyClass { Value = 2 } };List<MyClass> list2 = new List<MyClass> { new MyClass { Value = 1 }, new MyClass { Value = 2 } };bool areEqual = list1.Count == list2.Count && !list1.Except(list2).Any(); // TrueConsole.WriteLine($"list1 and list2 are equal: {areEqual}");}
}
  • 创建 list1 和 list2
    • list1 和 list2 是两个 List<MyClass>,它们各自包含两个 MyClass 对象,Value 分别为 1 和 2
  • 比较两个列表的内容
    • areEqual 变量的值是通过以下逻辑计算得到的:
      • 首先检查两个列表的元素数量是否相等(list1.Count == list2.Count)。
      • 然后使用 Except 方法找出 list1 中不在 list2 中的元素,如果没有这样的元素(即 !list1.Except(list2).Any() 为 true),则说明两个列表的内容相等。
  • 输出结果
    • 最后,使用 Console.WriteLine 输出两个列表是否相等的结果。

总结

  • 使用 SequenceEqual 是最简单和直接的方法,适用于顺序敏感的比较。
  • 使用 SetEquals 适用于无序比较。
  • 手动比较适用于需要自定义比较逻辑的情况。

其实这个修改BUG的方式是很蠢的,还是要从根源上分析为什么会出现两封一样的邮件。


BUG出现的原因

ET框架新起一个服务及实现服务之间的消息通讯_et startsceneconfig-CSDN博客

先说答案:出现这个BUG的原因是线上版本修改了Data服的配置文件(线上版本最开始的配置和本地文件相同,后来修改了Data服的线上版配置文件导致读取数据不一致) 


EmailManager组件放在了自己起的一个服务器Data服上,在SceneFactory添加组件的时候生成的ID和Data服StartSceneConfig@s.xlsx文件配置的ID相同。

比如你本地Data服配置的ID是10,那EmailManager组件保存到MongoDB中的ID也是10。因为修改了线上版本的配置文件,线上Data服配置的ID改为8,那EmailManager组件保存到MongoDB中的ID就多了一个8。

所以数据库中就会有ID为10的数据和ID为8的数据 。

体验服在程序启动的时候把ID为10和8的数据同时拉取了,之后运行过程中又是以ID为8的数据进行保存,所以服务器重启的时候又拉了一遍ID为10的数据造成不一致,让逻辑误以为邮件没领又重新拉了一遍。


解决办法 

解决办法就是在读取和保存数据的时候按照配置文件的ID进行动态操作(本地就用10,线上就用8)

public static async ETTask LoadEmailInfo(this EmailManagerComponent self)
{//按照配置文件ID进行读取数据: d.Id == self.DomainScene().Id  (self.DomainScene()是Data)var EmailManagerList =  await DBManagerComponent.Instance.GetZoneDB(self.DomainZone()).Query<EmailManagerComponent>(d => true && d.Id == self.DomainScene().Id,collection:"EmailManagerComponent");}//也可以通过条件: self.DomainScene().Name == "Data"  来筛选你要操作的数据

相关文章:

C#中判断两个 List<T> 的内容是否相等

ET实现游戏中邮件系统逻辑思路&#xff08;服务端&#xff09;_游戏邮件系统设计-CSDN博客 场景&#xff1a;今天遇到一个BUG&#xff0c;在服务器重启的时候&#xff08;体验服&#xff09;&#xff0c;玩家之前接收的邮件又重新接收了一次&#xff0c;但是两封邮件的ID是不同…...

Linux环境下配置neo4j图数据库

1.下载安装包 openjdk-11.0.1_linux-x64_bin.tar.gz neo4j-community-4.2.19-unix.tar.gz 2.之前配置好的配置文件 neo4j.conf 3.安装 3.1-jdk11的安装&#xff08;jdk1.8不够用&#xff09; 解压缩 tar -zxvf openjdk-11.0.1_linux-x64_bin.tar.gz修改系统环境变量 打开pro…...

Windows 11 搭建 Docker 桌面版详细教程

在当今的软件开发与部署领域&#xff0c;Docker 已成为一项极为重要的容器化技术。它能够让开发者轻松地打包应用及其依赖项&#xff0c;实现跨环境的一致性运行&#xff0c;大大提高了开发效率与部署的便捷性。本教程将详细介绍在 Windows 11 操作系统上搭建 Docker 桌面版的具…...

Pytest-Bdd-Playwright 系列教程(13):钩子(hooks)

Pytest-Bdd-Playwright 系列教程&#xff08;13&#xff09;&#xff1a;钩子&#xff08;hooks&#xff09; 前言一、什么是钩子&#xff1f;二、Pytest-Bdd 提供的钩子一览三、钩子用法详解1. pytest_bdd_before_scenario2. pytest_bdd_after_scenario3. pytest_bdd_before_s…...

dns 服务器简单介绍

dns 服务器分类&#xff1a; 根域名服务器顶级域名服务器权威域名服务器本地域名服务器 dns 的查询过程 国内优秀公共域名 腾讯&#xff1a;DNSPod-免费智能DNS解析服务商-电信_网通_教育网,智能DNS-烟台帝思普网络科技有限公司 119.29.29.29 和 182.254.118.118 阿里&#xf…...

Neo4j图形数据库-Cypher中常用指令

一、创建与修改 1.1 create 创建图数据库中的节点、关系等元素&#xff1a; CREATE (:Person {name: "Alice", age: 30}) CREATE (p1:Person {name: "Bob"})-[r:KNOWS]->(p2:Person {name: "Charlie"})批量创建元素 CREATE (n1:Node),(n2…...

linux安全管理-防火墙配置

1. 开启系统防火墙 1、检查内容 检查操作系统是否开启防火墙&#xff1b; 2、配置要求 操作系统开启防火墙&#xff1b; 3、配置方法 systemctl status firewalld ##查看系统防火墙运行状态 systemctl start firewalld ##启动防火墙 systemctl restart firewalld ##重启防火墙…...

什么是BIOS

BIOS&#xff08;Basic Input/Output System&#xff0c;基本输入输出系统&#xff09;是计算机启动过程中的一个关键组件&#xff0c;主要负责硬件的初始化和系统的引导。以下是关于 BIOS 的一些详细信息&#xff1a; 1. 基本功能 硬件初始化&#xff1a;当计算机启动时&…...

c++视频图像处理

打开视频或摄像头 打开指定视频 /*VideoCapture(const String &filename, apiPreference);filename:读取的视频或者图像序列的名称apiPreference&#xff1a;读取数据时设置的属性*/ VideoCapture video; //定义一个空的视频对象 video.open("H:/BaiduNetdiskDownlo…...

音视频入门基础:MPEG2-TS专题(8)——TS Header中的适配域

注&#xff1a;本文有部分内容引用了维基百科&#xff1a;https://zh.wikipedia.org/wiki/MPEG2-TS 一、引言 当TS Header中的adaptation_field_control属性的值为10或11 时&#xff0c;TS Header包含adaptation field&#xff08;适配域&#xff09;&#xff1a; 根据《T-RE…...

基于stm32单片机的教室节能系统设计

功能描述 0. STM32F103C8T6单片机为控制核心 1. OLED液晶显示当前年 月 日 时 分 秒 星期 2. 按键可以设置定时时间 3. 按键可以设置用电开关的开启和关闭时间&#xff0c;实现设备的节能 4. 通过红外遥控可以打开关闭空调设备&#xff08;通过继电器开关闭合模拟&#x…...

mini主机通过内网穿透做成服务器

文章目录 简介1.ubuntu 的ssh server 安装2.ubuntu 的docker 安装3.ubuntu的curl的安装4.ubuntu的frp客户端安装5.ubuntu的docker compose安装6.声明 简介 主要目的 本地设备做成服务器&#xff0c;实现ssh远程登录以及内网穿透设备总成本1千多元&#xff08;其实部分设备可以…...

智能桥梁安全运行监测系统守护桥梁安全卫士

一、方案背景 桥梁作为交通基础设施中不可或缺的重要组成部分&#xff0c;其安全稳定的运行直接关联到广大人民群众的生命财产安全以及整个社会的稳定与和谐。桥梁不仅是连接两地的通道&#xff0c;更是经济发展和社会进步的重要纽带。为了确保桥梁的安全运行&#xff0c;桥梁安…...

Selenium和Pyppeteer有什么区别?

Selenium和Pyppeteer都是自动化测试工具&#xff0c;它们可以模拟用户在浏览器中的操作&#xff0c;但它们之间存在一些关键的区别&#xff1a; Selenium 跨浏览器支持&#xff1a;Selenium支持多种浏览器&#xff0c;包括Chrome、Firefox、Internet Explorer等&#xff0c;而…...

82从零开始学Java之异常处理机制简介

作者:孙玉昌,昵称【一一哥】,另外【壹壹哥】也是我哦 CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者 前言 大家可以想一个问题,有没有谁能够做到开发项目时一个错误都不发生?如果谁能够做到这一点,那他可能真的是“天才”!但实际上,任何人都不可能在项目开发…...

Git上传本地项目到远程仓库(gitee/github)

目录 序言一、创建git本地版本库二、连接远程仓库&#xff08;以gitee为例&#xff09;三、将项目提交到git&#xff08;本地&#xff09;版本库1.由工作区添加到暂存区2.由暂存区添加到版本库 四、将代码由本地仓库上传到 gitee远程仓库1.获取远程库与本地同步2.把当前分支 ma…...

华为仓颉编程环境搭建

1、仓颉介绍 摘自华为官方&#xff1a;仓颉编程语言作为一款面向全场景应用开发的现代编程语言&#xff0c;通过现代语言特性的集成、全方位的编译优化和运行时实现、以及开箱即用的 IDE 工具链支持&#xff0c;为开发者打造友好开发体验和卓越程序性能。 其具体特性表现为&am…...

UE5 Line Trace By Channel(通道线条追踪)节点

在 Unreal Engine 5 (UE5) 中&#xff0c;Line Trace By Channel 是一个常用于进行物理射线检测&#xff08;raycasting&#xff09;的节点。它会沿着一条从起点到终点的直线发射一条射线&#xff0c;并检测射线与世界中任何物体的碰撞。这个节点广泛应用于枪械射击、检测物体、…...

DroneCAN 最新开发进展,Andrew在Ardupilot开发者大会2024的演讲

本文是Andrew演讲的中文翻译&#xff0c;你可以直接观看视频了解演讲的全部内容&#xff0c;此演讲视频的中文版本已经发布在Ardupilot社区的Blog板块&#xff0c;你可以在 Arudpilot官网&#xff08;https://ardupilot.org) 获取该视频&#xff1a; 你也可以直接通过Bilibili链…...

UDP客户端服务器通信

在这篇博客中&#xff0c;我们将探索 UDP&#xff08;用户数据报协议&#xff09; 通信&#xff0c;简要地说&#xff0c;UDP 是一种无连接、快速但不可靠的通信协议&#xff0c;适用于需要快速数据传输但对丢包容忍的场景&#xff0c;比如视频流和在线游戏。就像《我是如此相信…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...