当调用List Remove 失效时 [C#] .
有没有试过从一个集合里面移除一个对象之后,这个集合仍然留有这个对象?世界之大,无奇不有。稍有疏忽,便会导致这种奇怪的现象。现在让我们看看这个“不死”对象究竟是怎么一回事。
1、“不死”对象现身
这个问题起初是我一个同事提出的,为了重现“不死”对象,现把代码简化如下:





其中 Product 类代码如下:






























而 GetProduct 方法则根据传入的 ID 从数据库读取数据并返回,它的签名如下:



要想知道编号为 1412 的对象是否从 products 中移除,只需在 Code #01 的最后加上这样一行:



2、一不小心掉进陷阱
不知道你有没有查看 SDK 的习惯,其实 SDK 里面蕴藏着很多对我们解决问题有启发作用的信息的。现在让我们看看 SDK 里面能否找到什么蛛丝马迹。
由于 products 的真身是 List<T>,所以我们有必要看看 List<T> 是如何实现 IList.Remove 的:
This method determines equality using the default equality comparer EqualityComparer.Default for T, the type of values in the list.
原来,List<T> 在 IList.Remove 中使用 EqualityComparer.Default 来判断两个对象是否相等。那么 EqualityComparer.Default 又是如何得知两个对象是否相等呢?
The Default property checks whether type T implements the System.IEquatable generic interface and if so returns an EqualityComparer that uses that implementation. Otherwise it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T.
把上面这段话结合 Code #02 来看,我们可以发现 List<T> 中的 IList.Remove 判断两个 Product 对象是否相等的方法是从 Object 根类继承下来的 Equals 和 GetHashCode 方法,即比较两个对象的引用是否指向同一个对象。
由于 GetProduct 方法每次返回的都是一个新的对象(暂时让我们忘记对象缓存这家伙),于是就导致了集合里面出现“不死”对象。
3、不要被同一颗子弹打中两次
“不要被同一颗子弹打中两次”原意是指同一个错误不要两次犯,这句话暗含着对两个表示错误的对象进行逻辑上的判等,就像上面需要判断两个 Product 的对象在逻辑上是否相等那样。
至此,我们也知道了令 Remove 重新生效的两个可选办法是:
- 让 Product 类实现 IEquatable<T> 接口;
- 为 Product 类重写 Equals 和 GetHashCode 方法。
在大多数情况下,我们希望比较的并不是对象的引用,而是对象的内容,与此同时,我们又不太可能为了这些小对象劳师动众地实现对象缓存,于是,你就很有可能在类似的代码中邂逅“不死”对象了。
using System;
namespace DB_SecurityMonitor.Model
{
public partial class m_Sensor
{
public m_Sensor()
{}
#region Model
private int _id;
private string _vc_code;
private string _vc_memo;
public int ID
{
set{ _id=value;}
get{return _id;}
}
public string vc_Code
{
set{ _vc_code=value;}
get{return _vc_code;}
}
public string vc_Memo
{
set{ _vc_memo=value;}
get{return _vc_memo;}
}
#endregion Model
{
m_Sensor m = obj as m_Sensor;
if (this.ID == m.ID)
{
return true;
}
return false;
}
foreach (DB_SecurityMonitor.Model.m_Sensor item in lst)
{
lstMonitorSensor.Add(item);
}
foreach (DB_SecurityMonitor.Model.m_Sensor item in lst)
{
lstMonitorSensor.Remove(item);
}
当调用List Remove 失效时 [C#] .的更多相关文章
- memcached缓存失效时的高并发访问问题解决
memcached一般用于在访问一些性能相对低下的数据接口时(如数据库),为了保证这些数据接口的稳定性,加上memcached以减少访问次数,保证这些数据接口的健壮性.一般memcached的数据都是 ...
- Asp.Net调用Office组件操作时的DCOM配置 (转)
Asp.Net调用Office组件操作时的DCOM配置 http://blog.csdn.net/gz775/article/details/6447758 在项目中将数据导出为Excel格式时出现“ ...
- embed元素 autostart false 失效时的解决方法
embed元素 autostart false 失效时的解决方法 最近在工作中碰到了在网页中嵌入播放器播放声音文件的需求,最后使用了embed元素 代码如下: <embed src='1093. ...
- Rails : css或js文件无法成功预编译或调用jquery类插件时预编译问题
调用bootstrap css框架时,将bootstrap文件夹放入 vendor/assets/下 bootstrap文件结构如下: [shenma@localhost demo]$ ls v ...
- WebService调用一对多关联关系时出现 死循环:A cycle is detected in...
通过WebService调用一对多关联关系时引起的问题:A cycle is detected in the object graph 具体异常信息: org.apache.cxf.intercept ...
- 调用具体webservice方法时时报错误:请求因 HTTP 状态 503 失败: Service Temporarily Unavailable
添加web引用会在相应项目的app.cofig文件中产生如下代码: <sectionGroup name="applicationSettings" type="S ...
- ORA-39127: 调用 "WMSYS"."LT_EXPORT_PKG"."SCHEMA_INFO_EXP" 时发生意外错误
expdp 告警提示: Export: Release 11.2.0.4.0 - Production on 星期日 4月 28 12:14:51 2019....ORA-39127: 调用 &quo ...
- C#调用Oracle的存储过程时,连接字符串需要配置PLSQLRSet=1
C#调用Oracle的存储过程时, 如果有个SYS_REFCURSOR的Output参数存储时, web.config文件中的连接字符串需要配置PLSQLRSet=1, 否则可能会报这个错:参数个数或 ...
- dotnetcore ef 调用多个数据库时用户命令执行操作报错
dotnetcore ef 调用多个数据库时用户命令执行操作报错 1.多个DbContext 时报错: 报错: More than one DbContext was found. Specify w ...
随机推荐
- 程序语言的奥妙:算法解读 ——读书笔记
算法(Algorithm) 是利用计算机解决问题的处理步骤. 算法是古老的智慧.如<孙子兵法>,是打胜仗的算法. 算法是古老智慧的结晶,是程序的范本. 学习算法才能编写出高质量的程序. 懂 ...
- SpringMVC + Spring + MyBatis 学习笔记:在类和方法上都使用RequestMapping如何访问
系统:WIN8.1 数据库:Oracle 11GR2 开发工具:MyEclipse 8.6 框架:Spring3.2.9.SpringMVC3.2.9.MyBatis3.2.8 先看代码: @Requ ...
- HUE 安装
1.从github网下载hue-master.zip (源代码包) 地址:https://github.com/cloudera/hue#development-prerequisites 2.安装依 ...
- linux下设置SSH无密码登陆
SSH配置 主机cloudgis22.edu.cn:192.168.3.21 主机cloudgis33.edu.cn:192.168.2.174 假设需要配置主机A无密码登录主机A,主机B,先确保所有 ...
- dom 侧栏分享
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- <<海闻电子发票接口 ESB 封装 代码指示 文档>>
<<海闻电子发票接口 ESB 封装 代码指示 文档>> isValid 是否有效标志 代码 中文 说明 true 成功 false 失败 code 海闻错误说明 代码 中文 ...
- 如何通过写一个chrome扩展启动本地程序
@(编程) [toc] 本文介绍如何利用Chrome 的插件, 从我们的一个网站中启动一个我们的本地程序.本文的环境是windows10,本文的例子是通过点击网页上的一个button,调用本地的wor ...
- 一种将Region转为Polyline的方法
在AutoCAD.NET二次开发中,如果要将面域转为Polyline主要有以下几种方式: 1.使用Explode将面域炸成Line和Arc,然后再串起来,此方法可用于AutoCAD2007开始的所有版 ...
- HDU 2859 Phalanx (dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2859 给你一个n*n的矩阵,问你最大的对称度是多少(左下右上为对称线) dp[i][j]表示i行j列元 ...
- 无责任Windows Azure SDK .NET开发入门篇三[使用Azure AD 管理用户信息]
三.使用Azure AD管理用户信息 在上一章我们采用OpenID的方案和Azure AD交互进行身份验证,本章节我们继续了解如何在Azure AD中创建用户,列出用户信息,修改用户信息和删除用户信息 ...