有没有试过从一个集合里面移除一个对象之后,这个集合仍然留有这个对象?世界之大,无奇不有。稍有疏忽,便会导致这种奇怪的现象。现在让我们看看这个“不死”对象究竟是怎么一回事。

1、“不死”对象现身

这个问题起初是我一个同事提出的,为了重现“不死”对象,现把代码简化如下:

// Code #01

IList products = new List<Product>();
products.Add(GetProduct("1412"));
products.Remove(GetProduct("1412"));

其中 Product 类代码如下:

// Code #02

class Product
{
    public Product(string id)
    {
        m_ID = id;
    }

    private string m_ID;
    public string ID
    {
        get { return m_ID; }
    }

    public override string ToString()
    {
        return "ID: " + m_ID;
    }
}

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

// Code #03

public static Product GetProduct(string id);

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

// Code #04

Console.WriteLine(products.Count);

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 方法。

在大多数情况下,我们希望比较的并不是对象的引用,而是对象的内容,与此同时,我们又不太可能为了这些小对象劳师动众地实现对象缓存,于是,你就很有可能在类似的代码中邂逅“不死”对象了。

 
 
 
4 .例如有一个类

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

 
        重写Equals,判断当ID相等时就认为是相同的
        public override bool Equals(object obj)
        {
            m_Sensor m = obj as m_Sensor;
            if (this.ID == m.ID)
            {
                return true;
            }
            return false;
        }
}
 
 
            List<DB_SecurityMonitor.Model.m_Sensor> lst = new DB_SecurityMonitor.BLL.m_Sensor().GetModelList("i_flag=0");
            foreach (DB_SecurityMonitor.Model.m_Sensor item in lst)
            {
                lstMonitorSensor.Add(item);
            }
 
           List<DB_SecurityMonitor.Model.m_Sensor> lst = new DB_SecurityMonitor.BLL.m_Sensor().GetModelList("i_flag=0 and ID  in(104,113,99)");
            foreach (DB_SecurityMonitor.Model.m_Sensor item in lst)
            {
                lstMonitorSensor.Remove(item);
            }
 

当调用List Remove 失效时 [C#] .的更多相关文章

  1. memcached缓存失效时的高并发访问问题解决

    memcached一般用于在访问一些性能相对低下的数据接口时(如数据库),为了保证这些数据接口的稳定性,加上memcached以减少访问次数,保证这些数据接口的健壮性.一般memcached的数据都是 ...

  2. Asp.Net调用Office组件操作时的DCOM配置 (转)

    Asp.Net调用Office组件操作时的DCOM配置 http://blog.csdn.net/gz775/article/details/6447758 在项目中将数据导出为Excel格式时出现“ ...

  3. embed元素 autostart false 失效时的解决方法

    embed元素 autostart false 失效时的解决方法 最近在工作中碰到了在网页中嵌入播放器播放声音文件的需求,最后使用了embed元素 代码如下: <embed src='1093. ...

  4. Rails : css或js文件无法成功预编译或调用jquery类插件时预编译问题

    调用bootstrap css框架时,将bootstrap文件夹放入 vendor/assets/下 bootstrap文件结构如下:    [shenma@localhost demo]$ ls v ...

  5. WebService调用一对多关联关系时出现 死循环:A cycle is detected in...

    通过WebService调用一对多关联关系时引起的问题:A cycle is detected in the object graph 具体异常信息: org.apache.cxf.intercept ...

  6. 调用具体webservice方法时时报错误:请求因 HTTP 状态 503 失败: Service Temporarily Unavailable

    添加web引用会在相应项目的app.cofig文件中产生如下代码: <sectionGroup name="applicationSettings" type="S ...

  7. 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 ...

  8. C#调用Oracle的存储过程时,连接字符串需要配置PLSQLRSet=1

    C#调用Oracle的存储过程时, 如果有个SYS_REFCURSOR的Output参数存储时, web.config文件中的连接字符串需要配置PLSQLRSet=1, 否则可能会报这个错:参数个数或 ...

  9. dotnetcore ef 调用多个数据库时用户命令执行操作报错

    dotnetcore ef 调用多个数据库时用户命令执行操作报错 1.多个DbContext 时报错: 报错: More than one DbContext was found. Specify w ...

随机推荐

  1. Scrum角色

    产品负责人(Product Owner)的职责如下: 确定产品的功能. 决定发布的日期和发布内容. 为产品的profitability       of the product (ROI)负责. 根据 ...

  2. Linux+mysql+apache+php+wordpress搭建个人空间

    1.       linux的安装 现在Linux的品种巨多,这个你可以选择一个你喜欢的linux系统,如果是新手并不建议你使用freebsd,gentoo等,建议你可以安装ubuntu,如果要安装u ...

  3. OC使用inline替代宏

    CG_INLINE voidGCDDelay(int64_t delayInSeconds,dispatch_block_t block){ dispatch_time_t popTime = dis ...

  4. URAL-1987 Nested Segments 线段树简单区间覆盖

    题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1987 题意:给定n条线段,每两条线段要么满足没有公共部分,要么包含.给出m个询问,求当前 ...

  5. C_functions

    1.C常用函数分为如下几大类!! 1,字符测试函数. 2,字符串操作 3,内存管理函数 4,日期与时间函数 5,数学函数 6,文件操作函数 7,进程管理函数 8,文件权限控制 9,信号处理 10,接口 ...

  6. 【Maven】Maven下载源码和Javadoc的方法

    1:Maven命令下载源码和javadocs 当在IDE中使用Maven时如果想要看引用的jar包中类的源码和javadoc需要通过maven命令下载这些源码,然后再进行引入,通过mvn命令能够容易的 ...

  7. POJ 3177 Redundant Paths POJ 3352 Road Construction

    这两题是一样的,代码完全一样. 就是给了一个连通图,问加多少条边可以变成边双连通. 去掉桥,其余的连通分支就是边双连通分支了.一个有桥的连通图要变成边双连通图的话,把双连通子图收缩为一个点,形成一颗树 ...

  8. LightOJ 1282 Leading and Trailing (快数幂 + 数学)

    http://lightoj.com/volume_showproblem.php?problem=1282 Leading and Trailing Time Limit:2000MS     Me ...

  9. 巧解Tomcat中JVM内存溢出问题

    你对Tomcat 的JVM内存溢出问题的解决方法是否了解,这里和大家分享一下,相信本文介绍一定会让你有所收获. tomcat 的JVM内存溢出问题的解决 最近在熟悉一个开发了有几年的项目,需要把数据库 ...

  10. 在TFS2013上删除项目

    TFSDeleteProject 会永久性损坏团队项目,之后无法恢复该项目. 您应该在使用 TFSDeleteProject 之前备份所有重要的项目数据. 若要使用 TFSDeleteProject  ...