2016-03-02 1 views

Répondre

-2

Utiliser TryAdd(data) Méthode. Vous pouvez également transmettre un objet timespan ou int indiquant un délai d'expiration. Renvoie true ou false. Notez que si le type de collection sous-jacent ne peut pas gérer les doublons et que les données que vous essayez d'ajouter sont un doublon, un InvalidOperationException est déclenché.

+1

Toutes les classes sous-jacentes (IProdCons) acceptent les doublons, donc je ne pense pas que cela puisse être utile en soi. –

5

Vous devrez implémenter votre propre IProducerConsumerCollection<T> qui se comporte comme un ensemble (par exemple, aucun doublon n'est autorisé). Voici une version simpliste qui utilise une section critique (C# lock) pour le rendre thread-safe. Pour les scénarios de forte simultanéité, vous pouvez améliorer les performances en utilisant une classe telle que SpinWait de la même manière que ConcurrentQueue<T>.

public class ProducerConsumerSet<T> : IProducerConsumerCollection<T> { 

    readonly object gate = new object(); 

    readonly Queue<T> queue = new Queue<T>(); 

    readonly HashSet<T> hashSet = new HashSet<T>(); 

    public void CopyTo(T[] array, int index) { 
    if (array == null) 
     throw new ArgumentNullException("array"); 
    if (index < 0) 
     throw new ArgumentOutOfRangeException("index"); 
    lock (gate) 
     queue.CopyTo(array, index); 
    } 

    public bool TryAdd(T item) { 
    lock (gate) { 
     if (hashSet.Contains(item)) 
     return false; 
     queue.Enqueue(item); 
     hashSet.Add(item); 
     return true; 
    } 
    } 

    public bool TryTake(out T item) { 
    lock (gate) { 
     if (queue.Count == 0) { 
     item = default(T); 
     return false; 
     } 
     item = queue.Dequeue(); 
     hashSet.Remove(item); 
     return true; 
    } 
    } 

    public T[] ToArray() { 
    lock (gate) 
     return queue.ToArray(); 
    } 

    public void CopyTo(Array array, int index) { 
    if (array == null) 
     throw new ArgumentNullException("array"); 
    lock (gate) 
     ((ICollection) queue).CopyTo(array, index); 
    } 

    public int Count { 
    get { return queue.Count; } 
    } 

    public object SyncRoot { 
    get { return gate; } 
    } 

    public bool IsSynchronized { 
    get { return true; } 
    } 

    public IEnumerator<T> GetEnumerator() { 
    List<T> list = null; 
    lock (gate) 
     list = queue.ToList(); 
    return list.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() { 
    return GetEnumerator(); 
    } 

} 

Si nécessaire, vous pouvez élaborer sur cette classe pour personnaliser l'égalité en fournissant une option IEqualityComparer<T> qui est ensuite utilisé pour initialiser le HashSet<T>. Les méthodes IProducerConsumerCollection<T>.Add renvoient false lorsqu'une tentative d'insertion d'un élément en double est effectuée. Il en résulte une InvalidOperationException lancée par la méthode BlockingCollection<T>.Add de sorte que vous aurez probablement à envelopper le code pour ajouter un élément dans quelque chose comme ceci:

bool AddItem<T>(BlockingCollection<T> blockingCollection, T item) { 
    try { 
    blockingCollection.Add(item); 
    return true; 
    } 
    catch (InvalidOperationException) { 
    return false; 
    } 
} 

Notez que si vous ajoutez des éléments à une collection qui vous a été terminée vous renverront obtenir également un InvalidOperationException et vous devrez examiner le message d'exception pour déterminer la raison sous-jacente de l'exception.