Collection.Contains() 使用啥来检查现有对象?

Posted

技术标签:

【中文标题】Collection.Contains() 使用啥来检查现有对象?【英文标题】:What does Collection.Contains() use to check for existing objects?Collection.Contains() 使用什么来检查现有对象? 【发布时间】:2011-04-07 23:15:26 【问题描述】:

我有一个自定义对象的强类型列表MyObject,它有一个属性Id,以及其他一些属性。

假设MyObjectId 将其定义为唯一的,我想在添加我的新集合之前检查我的集合是否还没有Id 为1 的MyObject 对象MyObject 收藏。

我想使用if(!List<MyObject>.Contains(myObj)),但我如何强制执行MyObject 的只有一个或两个属性将其定义为唯一的事实?

我可以使用IComparable?还是我只需要覆盖Equals 方法?如果是这样,我需要先继承一些东西,对吗?

【问题讨论】:

【参考方案1】:

List<T>.Contains 使用 EqualityComparer<T>.Default,如果类型实现它,则反过来使用 IEquatable<T>,否则使用 object.Equals

你可以只实现IEquatable<T>,但如果你这样做,覆盖object.Equals是个好主意,如果你这样做,覆盖GetHashCode()是一个非常好主意:

public class SomeIDdClass : IEquatable<SomeIDdClass>

    private readonly int _id;
    public SomeIDdClass(int id)
    
        _id = id;
    
    public int Id
    
        get  return _id; 
    
    public bool Equals(SomeIDdClass other)
    
        return null != other && _id == other._id;
    
    public override bool Equals(object obj)
    
        return Equals(obj as SomeIDdClass);
    
    public override int GetHashCode()
    
        return _id;
    

请注意,哈希码与相等标准相关。这是至关重要的。

这也使它适用于任何其他情况,即通过具有相同 ID 定义的相等性是有用的。如果您有一个要求来检查列表是否有这样的对象,那么我可能会建议这样做:

return someList.Any(item => item.Id == cmpItem.Id);

【讨论】:

【参考方案2】:

List&lt;T&gt; 使用EqualityComparer&lt;T&gt;.Default 返回的比较器,并根据documentation 进行:

Default 属性检查是否 类型 T 实现 System.IEquatable(Of T) 接口和, 如果是,则返回 EqualityComparer(Of T) 使用该实现。 否则,它返回一个 EqualityComparer(Of T) 使用 覆盖 Object.Equals 和 Object.GetHashCode 由 T 提供。

因此,您可以在自定义类上实现IEquatable&lt;T&gt;,或覆盖Equals(和GetHashCode)方法以根据您需要的属性进行比较。或者,您可以使用 linq:

bool contains = list.Any(i => i.Id == obj.Id);

【讨论】:

我会选择 Linq 语句。如果你愿意,你可以实现一个扩展方法 Contains(this List list, T item, Func comparer),它看起来像 List.Contains,但增加了提供比较的能力代表。它将包装一个类似于此处提供的 Linq 语句。 +1 也适用于 LINQ,因为它允许您比较来自外部源的类。为了代码优雅【参考方案3】:

您可以使用 LINQ 轻松完成此操作。

var result = MyCollection.Any(p=>p.myId == Id);
if(result)

     //something

【讨论】:

甜蜜。好点子!对你们俩+1。随心所欲地花钱。 我要把这一切都吹到帽子上。【参考方案4】:

您可以覆盖 Equals 和 GetHashCode,实现 IEqualityComparer&lt;MyObject&gt; 并在 Contains 调用中使用它,或者使用像 Any 这样的扩展方法

if (!myList.Any(obj => obj.Property == obj2.Property && obj.Property2 == obj2.Property2))
   myList.Add(obj2);

【讨论】:

+1,这是一个很好的高性能解决方案,尤其是在您使用集合或字典时。 (说到 Equals/GetHashCode 点)【参考方案5】:

首先用 IEqualityComparer 定义辅助类。

public class MyEqualityComparer<T> : IEqualityComparer<T>

    Func<T, int> _hashDelegate;

    public MyEqualityComparer(Func<T, int> hashDelegate)
    
        _hashDelegate = hashDelegate;
    

    public bool Equals(T x, T y)
    
        return _hashDelegate(x) == _hashDelegate(y);
    

    public int GetHashCode(T obj)
    
        return _hashDelegate(obj);
    

然后在你的代码中,定义比较器并使用它:

var myComparer = new MyEqualityComparer<MyObject>(delegate(MyObject obj)
    return obj.ID;
);

var result = collection
   .Where(f => anotherCollection.Contains(f.First, myComparer))
   .ToArray();

通过这种方式,您可以在不修改类的情况下定义 Equality 的计算方式。您也可以使用它来处理来自第三方库的对象,因为您无法修改他们的代码。

【讨论】:

【参考方案6】:

您可以使用IEquatable&lt;T&gt;。在你的类中实现它,然后检查传递给 Equals 的 T 是否与 this.Id 具有相同的 Id。我确信这适用于检查字典中的键,但我没有将它用于集合。

【讨论】:

以上是关于Collection.Contains() 使用啥来检查现有对象?的主要内容,如果未能解决你的问题,请参考以下文章

包含 Iterable 和 Iterator 的方法?

我们啥时候应该使用互斥锁,啥时候应该使用信号量

Flutter 中 required 和 @required 有啥区别。它们之间有啥区别,我们啥时候需要使用它们?

c#啥时候应该使用List,啥时候应该使用arraylist?

你啥时候把 Javascript 放在 body 里,啥时候放在 head 里,啥时候使用 doc.load? [复制]

我啥时候使用 ,啥时候不在 JavaScript 中导入 [重复]