为什么ConcurrentBag <T>不实现ICollection <T>?

我有一个方法需要IList <>并添加内容。 我想在某些情况下将它传递给一个ConcurrentBag,但它不实现IList <>或ICollection <>,只有非泛型ICollection没有Add方法。

现在,我明白了为什么它不能(可能)实现IList - 它不是一个有序的集合,所以它没有任何意义,因为它有一个索引器。 但是我没有看到任何ICollection <>方法的问题。

所以为什么? 而且,在.NET中是否有一个线程安全的集合,它实现了更强大的接口?


List<T>不是并发的,所以它可以实现ICollection<T> ,它给你一对方法ContainsAdd 。 如果Contains返回false ,则可以安全地调用Add知道它会成功。

ConcurrentBag<T>是并发的,因此无法实现ICollection<T>因为在您调用Add时,答案Contains返回可能无效。 相反,它实现了IProducerConsumerCollection<T>它提供了一个方法TryAdd ,做的工作都ContainsAdd

所以不幸的是,你希望对两个既是集合又不共享通用接口的东西进行操作。 有很多方法可以解决这个问题,但是当API与这些API类似时,我的首选方法是为两个接口提供方法重载,然后使用lambda表达式构造使用各自的方法为每个接口执行相同操作的委托。 然后,您可以使用该委托来代替您将执行几乎常见操作的位置。

这里有一个简单的例子:

public class Processor
{
    /// <summary>
    /// Process a traditional collection.
    /// </summary>
    /// <param name="collection">The collection.</param>
    public void Process(ICollection<string> collection)
    {
        Process(item =>
            {
                if (collection.Contains(item))
                    return false;
                collection.Add(item);
                return true;
            });
    }

    /// <summary>
    /// Process a concurrent collection.
    /// </summary>
    /// <param name="collection">The collection.</param>
    public void Process(IProducerConsumerCollection<string> collection)
    {
        Process(item => collection.TryAdd(item));
    }

    /// <summary>
    /// Common processing.
    /// </summary>
    /// <param name="addFunc">A func to add the item to a collection</param>
    private void Process(Func<string, bool> addFunc)
    {
        var item = "new item";
        if (!addFunc(item))
            throw new InvalidOperationException("duplicate item");
    }
}

并不是ConcurrentBag<T>无法实现ICollection<T> ; 你大概可以想像, Contains可以采用以下方式实现TryPeek ,或RemoveTryTake

问题在于将ConcurrentBag<T>当作ICollection<T> (例如,通过在将ConcurrentBag<T>传递给仅采用ICollection<T>的方法时允许隐式转换)是不明智的,因为大多数消费者ICollection<T>期望它与ConcurrentBag<T>具有明显不同的语义。

ICollection<T>作为参数的大多数方法都可能会做出假设(在单线程场景中是安全的),比如“ Add后跟Contains将始终返回true ”,或者“如果Contains返回true ,那么将会Remove “。 但是,在高度多线程的情况下(首先可能会使用ConcurrentBag<T> ),这些假设不太可能成立。 这可能会暴露在假设在单线程场景中使用ICollection<T>编写的代码中的错误。

如果你确实需要将ConcurrentBag<T>公开为ICollection<T> (并且你知道你传递给它的代码期望它以非ICollection<T>方式工作),它应该相当简单编写一个包装类(使用适配器模式)来使用ConcurrentBag<T>上最接近的可用方法来模拟ICollection<T>的方法。


SynchronizedCollection<T> ,实现IList<T>ICollection<T>以及IEnumerable<T>

链接地址: http://www.djcxy.com/p/64329.html

上一篇: Why doesn't ConcurrentBag<T> implement ICollection<T>?

下一篇: XML Serialization for collection types