笛卡尔积

导航

关于List<T>中的Exists 和Contains的区别

转载:http://www.cnblogs.com/jicheng1014/archive/2010/02/01/1660967.html

 

 

今天在做小项目的时候,有个需求,是比较List 中的对象是否存在过

而比较的对象是通过新建得来的(反序列化)

正当我使用Contains做比较的时候,

就发现问题了.

以下是测试代码

[TestMethod()]
public void RemoveDiscendantPowerTest() {
    Power Parent = new Power
    {
        Alias = "testRoot",
        CanDelete = false,
        Description = "测试根目录",
        id = 100,
        PowerName = "测试根目录",
        Childs = new List<Power>
        {
            new Power{
                Alias = "testBranch1",
                CanDelete = true,
                Description = "枝干节点1",
                id = 100100,
                PowerName = "枝干节点1",
                Childs = new List<Power>{
                    new Power{
                     Alias = "leaf1",
                     CanDelete = true,
                     Description = "叶子节点1",
                     id = 100100100,
                     PowerName = "叶子节点1"
                    },
                    new Power{
                     Alias = "leaf2",
                     CanDelete = true,
                     Description = "叶子节点2",
                     id = 100100101,
                     PowerName = "叶子节点2"
                    }
                }
            },
            new Power{
                Alias ="testBranch2",
                CanDelete = true,
                Description = "枝干节点2",
                id = 100101,
                PowerName = "枝干接点2",
                Childs = new List<Power>{
                    new Power{
                     Alias = "leaf3",
                     CanDelete = true,
                     Description = "叶子节点3",
                     id = 100101100,
                     PowerName = "叶子节点3"
                    },
                    new Power{
                     Alias = "leaf4",
                     CanDelete = true,
                     Description = "叶子节点4",
                     id = 100101101,
                     PowerName = "叶子节点4"
                    }
                }
                
            }
        }
    }; // TODO: 初始化为适当的值
    Power Discendant = new Power{
                     Alias = "leaf4",
                     CanDelete = true,
                     Description = "叶子节点4",
                     id = 100101101,
                     PowerName = "叶子节点4"
                    };
    // TODO: 初始化为适当的值
 
 
    Assert.IsTrue(Parent.Childs[1].Childs.Contains(Discendant), "测试失败,Contains 不能抓出");
 
 
 
 
}

 

 

测试结果如下:

image

结论是,新建的一模一样的对象却在Contains 中返回的false,未能通过测试

为什么会出现这种问题呢?

答案很简单:Contains比较的是存储的内存地址是否相同,而不是值相同.

我们更改下测试,就能发现问题了

/// <summary>
///RemoveDiscendantPower 的测试
///</summary>
[TestMethod()]
public void RemoveDiscendantPowerTest() {
    Power Parent = new Power
    {
        Alias = "testRoot",
        CanDelete = false,
        Description = "测试根目录",
        id = 100,
        PowerName = "测试根目录",
        Childs = new List<Power>
        {
            new Power{
                Alias = "testBranch1",
                CanDelete = true,
                Description = "枝干节点1",
                id = 100100,
                PowerName = "枝干节点1",
                Childs = new List<Power>{
                    new Power{
                     Alias = "leaf1",
                     CanDelete = true,
                     Description = "叶子节点1",
                     id = 100100100,
                     PowerName = "叶子节点1"
                    },
                    new Power{
                     Alias = "leaf2",
                     CanDelete = true,
                     Description = "叶子节点2",
                     id = 100100101,
                     PowerName = "叶子节点2"
                    }
                }
            },
            new Power{
                Alias ="testBranch2",
                CanDelete = true,
                Description = "枝干节点2",
                id = 100101,
                PowerName = "枝干接点2",
                Childs = new List<Power>{
                    new Power{
                     Alias = "leaf3",
                     CanDelete = true,
                     Description = "叶子节点3",
                     id = 100101100,
                     PowerName = "叶子节点3"
                    },
                    new Power{
                     Alias = "leaf4",
                     CanDelete = true,
                     Description = "叶子节点4",
                     id = 100101101,
                     PowerName = "叶子节点4"
                    }
                }
                
            }
        }
    }; // TODO: 初始化为适当的值
    Power Discendant = new Power{
                     Alias = "leaf4",
                     CanDelete = true,
                     Description = "叶子节点4",
                     id = 100101101,
                     PowerName = "叶子节点4"
                    };
    // TODO: 初始化为适当的值
 
 
    //Assert.IsTrue(Parent.Childs[1].Childs.Contains(Discendant), "测试失败,Contains不能抓出");
 
 
 
    Power test = Parent.Childs[1].Childs[1];
 
    Assert.IsTrue(Parent.Childs[1].Childs.Contains(test), "测试失败,甚至连内存引用都扯淡");
 
 
}

结果为

image

 

很显然,当我直接从Parent中取得一个对象的时候,Contains就会抓住这个对象

 

那么,如果说我需要值的比较的话,怎样做到呢?

 

很简单,我们可以定义一个predicate 委托来指定怎样进行比较:

/// <summary>
///RemoveDiscendantPower 的测试
///</summary>
[TestMethod()]
public void RemoveDiscendantPowerTest() {
    Power Parent = new Power
    {
        Alias = "testRoot",
        CanDelete = false,
        Description = "测试根目录",
        id = 100,
        PowerName = "测试根目录",
        Childs = new List<Power>
        {
            new Power{
                Alias = "testBranch1",
                CanDelete = true,
                Description = "枝干节点1",
                id = 100100,
                PowerName = "枝干节点1",
                Childs = new List<Power>{
                    new Power{
                     Alias = "leaf1",
                     CanDelete = true,
                     Description = "叶子节点1",
                     id = 100100100,
                     PowerName = "叶子节点1"
                    },
                    new Power{
                     Alias = "leaf2",
                     CanDelete = true,
                     Description = "叶子节点2",
                     id = 100100101,
                     PowerName = "叶子节点2"
                    }
                }
            },
            new Power{
                Alias ="testBranch2",
                CanDelete = true,
                Description = "枝干节点2",
                id = 100101,
                PowerName = "枝干接点2",
                Childs = new List<Power>{
                    new Power{
                     Alias = "leaf3",
                     CanDelete = true,
                     Description = "叶子节点3",
                     id = 100101100,
                     PowerName = "叶子节点3"
                    },
                    new Power{
                     Alias = "leaf4",
                     CanDelete = true,
                     Description = "叶子节点4",
                     id = 100101101,
                     PowerName = "叶子节点4"
                    }
                }
                
            }
        }
    }; // TODO: 初始化为适当的值
    Power Discendant = new Power{
                     Alias = "leaf4",
                     CanDelete = true,
                     Description = "叶子节点4",
                     id = 100101101,
                     PowerName = "叶子节点4"
                    };
    // TODO: 初始化为适当的值
 
 
    //Assert.IsTrue(Parent.Childs[1].Childs.Contains(Discendant), "测试失败,Contains不能抓出");
 
 
 
    //Power test = Parent.Childs[1].Childs[1];
 
    //Assert.IsTrue(Parent.Childs[1].Childs.Contains(test), "测试失败,甚至连内存引用都扯淡");
    Assert.IsTrue(Parent.Childs[1].Childs.Exists(delegate(Power t) {
        return t.id == 100101101;
    }));
 
}

(此处使用匿名委托代替了显式声明一个Predicate 委托)

测试轻松通过

image

 

ok,委托的比较执行成功.

 

结论

================================

List<T> 中的Contains 是对对象的"内存检测",

如果想查看List<T> 中是否有个对象的值   跟你声明的对象的值相同

则我们需要Exists 方法,且实现一个Predicate 委托来指定比较的方式

================================

posted on 2010-02-01 16:12  rabow  阅读(1324)  评论(0编辑  收藏  举报