.net 加速列表.contains

.net 加速列表.contains,.net,list,generics,.net,List,Generics,我们有一个C#library类,它从列表中继承,但速度很慢,因为List.Contains很慢。我们不能将该类更改为从其他对象(如字典或哈希集)继承,因为很多客户端代码都依赖于该类,而且该类太复杂,无法更改接口。有没有一种简单的方法可以在不改变它的情况下加速此方法?有些列表非常大,所以我们不希望在内存中有两个副本。我们也不想覆盖列表的每个方法 public class UniqueList<T> : List<T>, IList<T> { public

我们有一个C#library类,它从列表中继承,但速度很慢,因为List.Contains很慢。我们不能将该类更改为从其他对象(如字典或哈希集)继承,因为很多客户端代码都依赖于该类,而且该类太复杂,无法更改接口。有没有一种简单的方法可以在不改变它的情况下加速此方法?有些列表非常大,所以我们不希望在内存中有两个副本。我们也不想覆盖列表的每个方法

public class UniqueList<T> : List<T>, IList<T>
{
    public new void Add(T item)
    {
        if (!this.Contains(item) && item != null)
        {
            base.Add(item);
        }
    }
公共类唯一列表:列表,IList
{
新增公共作废(T项)
{
如果(!this.Contains(item)&&item!=null)
{
基础。添加(项目);
}
}

你可以拥有一个类级私有字典,如果在字典中找不到它,则先签入字典,然后转到列表并检查,这只是一个优化,不是纯粹的解决方案,还需要花费额外的内存

你可以拥有一个类级私有字典,如果它不存在,则先签入字典在字典中,然后转到列表并检查,这只是一个优化,不是纯粹的解决方案,还需要花费额外的内存,从列表继承是一个非常糟糕的主意,因为您无法控制客户端代码如何使用您的类

List.Contains是一个O(n)操作。Dictionary.ContainsKey是一个O(1),因此我认为使用Dictionary是最好的建议,但如果您确实不想使用它,另一种可能是保持列表排序以获得O(log n)

公共作废添加(T项)
{
int index=二进制搜索(项);
如果(指数<0)
{
插入(~索引,项目);
}
}
如果元素已经在列表中,BinarySearch将返回其索引。 如果元素不在列表中,BinarySearch方法将返回一个负数,该负数是第一个元素索引的二进制补码,该索引大于我传递给BinarySearch方法的元素

在您的场景中,可能无法使用BinarySearch,因为它取决于T可以是什么:


此方法使用默认比较器comparer.default类型T来确定列表元素的顺序。comparer.default属性检查类型T是否实现IComparable泛型接口并使用该实现(如果可用)。如果不实现,则检查comparer.default类型T是否实现IComparable接口。如果类型T不实现Comparer,这两个接口都没有实现。默认值会引发InvalidOperationException。

从列表继承是一个非常糟糕的主意,因为您无法控制客户端代码如何使用类

List.Contains是一个O(n)操作。Dictionary.ContainsKey是一个O(1),因此我认为使用Dictionary是最好的建议,但如果您确实不想使用它,另一种可能是保持列表排序以获得O(log n)

公共作废添加(T项)
{
int index=二进制搜索(项);
如果(指数<0)
{
插入(~索引,项目);
}
}
如果元素已经在列表中,BinarySearch将返回其索引。 如果元素不在列表中,BinarySearch方法将返回一个负数,该负数是第一个元素索引的二进制补码,该索引大于我传递给BinarySearch方法的元素

在您的场景中,可能无法使用BinarySearch,因为它取决于T可以是什么:

此方法使用默认比较器comparer.default类型T来确定列表元素的顺序。comparer.default属性检查类型T是否实现IComparable泛型接口并使用该实现(如果可用)。如果不实现,则检查comparer.default类型T是否实现IComparable接口。如果类型T不实现s未实现任何一个接口,Comparer。默认值引发InvalidOperationException。

简言之,否

因为您是从
List
继承的,所以您基本上被搞砸了,因为即使您对Contains方法进行了阴影处理,您也无法阻止客户端代码将
UniqueList
传递给接受
List
的方法,这将隐藏新的contain,并使用现有的contain

您需要以艰难的方式解决这个问题,删除
列表
上的继承,实现您自己的Contains,从列表中重新实现您需要的任何方法(在内部,您可以使用
私有列表
进行存储,并在必要时简单地委托给该列表),并修复此更改中断的所有代码

当你在破坏东西的时候,你可以看看C5集合类,它促进了对接口的开发,帮助你不碰到这个问题(我知道,在马跑了以后,更多地关上谷仓的门)

我知道这不是你想要的答案,但你不会得到你想要的答案(真的没有办法对此进行编程,你可以尝试类似的方法,但我认为它们在这种情况下不起作用……但我不能确定它们不会起作用)

再次为未能提供实际帮助表示歉意。

简言之,不

因为您是从
List
继承的,所以您基本上被搞砸了,因为即使您对Contains方法进行了阴影处理,您也无法阻止客户端代码将
UniqueList
传递给接受
List
的方法,这将隐藏新的contain,并使用现有的contain

您需要以艰难的方式解决这个问题,删除
列表
上的继承,实现您自己的Contains,从列表中重新实现您需要的任何方法(在内部,您可以使用
私有列表
进行存储,并在必要时简单地委托给该列表),并修复此更改中断的所有代码

当你打破了一些东西时,你可以看看C5集合类,它促进了对接口的开发,帮助你避免了这个问题(我知道,更多的是关上仓库的门)
public void Add(T item)
{
    int index = BinarySearch(item);
    if (index < 0)
    {
        Insert(~index, item);
    }
}