如何知道IEnumerable是否与其他集合相同?

问题描述

我有一个带有哈希集的类作为集合。有时,我将此哈希集作为参数传递给方法,但参数为IEnumerable

在这方法中,我想检查对象的参数和属性是否为同一集合,以避免在集合相同的情况下执行任何操作。

班级是这个:

MyClass
{
    HashSet<MyType> MyCollection;

    public void MyMethod(IEnumerable<MyType> param)
    {
       if(this.MyCOllecction != param)
       {
           this.MyCollection.Clear();
           this.MyCollection.AddRange(param);
       }
    }
}

问题在于if是否为true,因此它将处理集合。问题在于最终结果是MyCollection为空,因为首先我清除了集合,所以当IEnumerable参数尝试访问集合中的元素时,它为空,因此最终结果是MyCollection为空。应该再次添加MyCollection拥有的元素。

我想知道如何知道IEnumerable是否将访问MyCollection属性或另一个不同的集合。

谢谢

解决方法

不可能可靠地优化此方法,因为无法确定传递给该方法的集合是否与该类所持有的集合相同。

您可能会认为您可以使用object.Equals()进行检查,这确实适用于某些情况-但并非适用于所有情况。考虑以下代码:

HashSet<int> hashset = new HashSet<int>();

IEnumerable<int> test1 = hashset;
IEnumerable<int> test2 = hashset;

// Prints "equal"
Console.WriteLine(object.Equals(test1,test2) ? "equal" : "not equal");

test1 = hashset.AsEnumerable();
test2 = hashset.AsEnumerable();

// Prints "equal"
Console.WriteLine(object.Equals(test1,test2) ? "equal" : "not equal");

test1 = hashset;
test2 = hashset.Select(item => item);

// Prints "not equal". Oh dear.
Console.WriteLine(object.Equals(test1,test2) ? "equal" : "not equal");

因此,这表明仅基于对象引用相等性就不可能可靠地对其进行优化。

此外,您声明元素数量很少-因此不需要优化。

如果您真的想安全地优化此操作,则可以执行以下操作:

public void MyMethod(IEnumerable<MyType> param)
{
    if (!object.Equals(this.MyCollection,param))
    {
        this.MyCollection = new HashSet<MyType>();
        this.MyCollection.AddRange(param);
    }

    // ...
}

但是我认为这种优化并不是真正必要的,因此您可以将其实现为:

public void MyMethod(IEnumerable<MyType> param)
{
    this.MyCollection = new HashSet<MyType>();
    this.MyCollection.AddRange(param);

    // ...
}

您将必须在代码中使用实际类型,而不要使用没有HashSet方法的AddRange()。您问题中的代码显然不是您的实际代码...

,

问题尚不清楚-same可能表示相同的实例或包含相同的数据。原始代码无论如何都无法正常工作,因为HashSet没有AddRange

替换存储集

处理此问题的一种可能方法是使用模式匹配来检查输入是否为HashSet,且该实例与存储的实例相同:

public void MyMethod(IEnumerable<MyType> param)
{
   if(param is HashSet<MyType> h && h.ReferenceEquals(MyCollection))
   {
       return;
   }
   MyCollection=new HashSet<MyType>(param);
}

合并新值

HashSet没有AddRange,因此原始代码仍然无法正常工作。等效为UnionWith,它将添加 only 个新项目。这比使用SequenceEquals然后添加新项目要快,因为HashSet已针对集合操作进行了优化:

public void MyMethod(IEnumerable<MyType> param)
{
   if(param is HashSet<MyType> h && h.ReferenceEquals(MyCollection))
   {
       return;
   }
   MyCollection.UnionWith(param);
}