Does a non-concurrent bag exist - c#

Is there such a thing as a non-concurrent bag? I see lots of mentions of ConcurrentBag, but nothing about Bag.
Does such a collection exist?
To clarify why I'd like to use such a collection, I often find that the order of a collection becomes an important but potentially difficult to trace property of a collection.
I'm not necessarily saying that this would often happen in good, well designed code, but there are situations where I wish I could say "do not expect any order on this collection, order it specifically as and when you need to".

No, but since it documented as being "optimized for scenarios where the same thread will be both producing and consuming data stored in the bag", you can just use ConcurrentBag in both concurrent and non-concurrent scenarios.

You could always write your own class that "hides" the order of the items.
For example:
public sealed class NonConcurrentBag<T>: IReadOnlyCollection<T>
{
public void Add(T item)
{
// When adding an item, add it to a random location to avoid callers assuming an ordering.
if (_items.Count == 0)
{
_items.Add(item);
return;
}
int index = _rng.Next(0, _items.Count);
_items.Add(_items[index]);
_items[index] = item;
}
public void Clear()
{
_items.Clear();
}
public T Take()
{
if (_items.Count == 0)
throw new InvalidOperationException("Attempting to Take() from an empty NonConcurrentBag");
var result = _items[_items.Count - 1];
_items.RemoveAt(_items.Count - 1);
return result;
}
public bool IsEmpty => _items.Count == 0;
public IEnumerator<T> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count => _items.Count;
readonly List<T> _items = new List<T>();
readonly Random _rng = new Random();
}
When you add an item, this sneakily adds it at a random index (shifting the displaced item to the end of the list).
That means that not only is the index of an item random when you add it, it can also move to a different index as you add more items. That'll foil anything that expects any particular order!
Adding and taking items is an O(1) operation except when adding and the underlying list needs to be resized, when it is an O(N) operation.

Related

ConcurrentDictionary with multiple values per key, removing empty entries

ConcurrentDictionary works well for concurrent situations when mapping keys to a single value each. When mapping to multiple values, it is easy to create a ConcurrentDictionary<K, List<V>> and guard its addition/removal functions.
ConcurrentDictionary <string, List<string>> d;
// Add
var list = d.GetOrAdd ("key", x => new List<string> ());
lock (list) {
list.Add ("value to add");
}
// Remove
if (d.TryGetValue ("key", out var list)) {
lock (list) {
list.Remove ("value to remove");
}
}
However, the above assumed that empty lists are allowed to stay. I don't want that. But removing empty pairs does not seem to be possible in an atomic fashion. One might try:
if (d.TryGetValue ("key", out var list)) {
lock (list) {
if (list.Remove ("value to remove") && list.Count == 0) {
d.TryRemove ("key", out _);
}
}
}
But this has a race condition when another thread grabs the list before but adds to it after it was emptied and removed elsewhere:
A: get list
B: get list
B: lock, remove from list
B: list is empty, delete key, unlock
A: lock, add to list, unlock
Locking on the dictionary is not possible (it's a different use case).
As far as I can tell, a solution would usually be found using compare-and-swap operations and replacing the list with e.g. an immutable array that is then replaced in its entirety. However, given that ConcurrentDictionary does not offer a TryRemove with an expected value to compare against, I don't quite see how. Possibly there is a two-stage solution?
Using the out parameter of TryRemove to add values again after removing them (to fix race cases) is not possible - the dictionary would briefly be in an inconsistent state.
There are many questions on this site asking about similar scenarios, but most of them suffer from trivial mistakes or do not remove empty entries. There is this highly related question which asks if it is possible to do this. Sadly, it is five years old, received very little attention and has no solution apart from resorting to locks (which defeats the purpose). Possibly there opened up a better way since that time.
(Edited example for clarity)
I managed to implement a ConcurrentMultiDictionary class that stores multiple values per key, and with empty entries removed. The values of each key are stored in a HashSet, so each key has unique values. This increases the performance of deleting a value when the number of values is large. If the uniqueness is a problem then the HashSet should be replaced with a List, and the Add method should be modified to return void instead of bool.
The atomicity of the adding and removing operations is achieved by spinning. When a bag of values becomes empty, it is flagged as "discarded". Adding values into a discarded bag is not allowed, so the Add operation spins until it grabs a non discarded bag. The Remove operation spins too. So the only thread that is allowed to remove a discarded bag is the same thread that marked the bag as discarded. All other threads will be spinning until that happens. SpinWait structs are used for the spinning, to ensure efficiency even in single processor machines.
An unsolvable problem of this implementation is how to implement a ToArray method that takes a snapshot of all keys and values stored in the dictionary. The ConcurrentDictionary.ToArray method returns a snapshot of the keys, but the bags can be constantly changing, and this is why I believe it is unsolvable.
Even implementing the IEnumerable interface is a bit tricky, because if we just enumerate the KeyValuePairs of the underlying dictionary, most of the bags could be discarded at the time their values are acquired. So during the enumeration the bag of each key is retrieved individually, to be as current as possible.
public class ConcurrentMultiDictionary<TKey, TValue>
: IEnumerable<KeyValuePair<TKey, TValue[]>>
{
private class Bag : HashSet<TValue>
{
public bool IsDiscarded { get; set; }
}
private readonly ConcurrentDictionary<TKey, Bag> _dictionary;
public ConcurrentMultiDictionary()
{
_dictionary = new ConcurrentDictionary<TKey, Bag>();
}
public int Count => _dictionary.Count;
public bool Add(TKey key, TValue value)
{
var spinWait = new SpinWait();
while (true)
{
var bag = _dictionary.GetOrAdd(key, _ => new Bag());
lock (bag)
{
if (!bag.IsDiscarded) return bag.Add(value);
}
spinWait.SpinOnce();
}
}
public bool Remove(TKey key, TValue value)
{
var spinWait = new SpinWait();
while (true)
{
if (!_dictionary.TryGetValue(key, out var bag)) return false;
bool spinAndRetry = false;
lock (bag)
{
if (bag.IsDiscarded)
{
spinAndRetry = true;
}
else
{
bool valueRemoved = bag.Remove(value);
if (!valueRemoved) return false;
if (bag.Count != 0) return true;
bag.IsDiscarded = true;
}
}
if (spinAndRetry) { spinWait.SpinOnce(); continue; }
bool keyRemoved = _dictionary.TryRemove(key, out var currentBag);
Debug.Assert(keyRemoved, $"Key {key} was not removed");
Debug.Assert(bag == currentBag, $"Removed wrong bag");
return true;
}
}
public bool TryGetValues(TKey key, out TValue[] values)
{
if (!_dictionary.TryGetValue(key, out var bag)) { values = null; return false; }
bool isDiscarded;
lock (bag) { isDiscarded = bag.IsDiscarded; values = bag.ToArray(); }
if (isDiscarded) { values = null; return false; }
return true;
}
public bool Contains(TKey key, TValue value)
{
if (!_dictionary.TryGetValue(key, out var bag)) return false;
lock (bag) return !bag.IsDiscarded && bag.Contains(value);
}
public bool ContainsKey(TKey key) => _dictionary.ContainsKey(key);
public ICollection<TKey> Keys => _dictionary.Keys;
public IEnumerator<KeyValuePair<TKey, TValue[]>> GetEnumerator()
{
foreach (var key in _dictionary.Keys)
{
if (this.TryGetValues(key, out var values))
{
yield return new KeyValuePair<TKey, TValue[]>(key, values);
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
This implementation was tested with 8 concurrent workers mutating a dictionary a million times per worker, and no inconsistency regarding the reported number of additions and removals was observed.
There seems to be no practical way of removing an empty collection (even if it is synchronized) from a concurrent dictionary without having race condition issues. There are certain facts preventing this from being possible, as discussed in the comments under both the question and the OP's self answer.
What I wrote in my comment, however, seemed feasible and I wanted to give it a try.
I want to discuss the drawbacks of this implementation right after, and I should also say that your comments (if received any) are what is most valuable to me.
First, the usage:
static void Main(string[] args)
{
var myDictionary = new ConcurrentDictionary<string, IList<int>>();
IList<int> myList = myDictionary.AddSelfRemovingList<string, int>("myList");
myList.Add(5);
myList.Add(6);
myList.Remove(6);
myList.Remove(5);
IList<int> existingInstance;
// returns false:
bool exists = myDictionary.TryGetValue("myList", out existingInstance);
// throws HasAlreadyRemovedSelfException:
myList.Add(3);
}
AddSelfRemovingList is an extension method to make things easier.
For the discussion part:
It is not acceptable for the removal of an item from a collection to have a side effect of removing the collection reference from the owning dictionary.
It is also not good practice to make the collection obsolete (unusable) when all its items are removed. There is a strong possibility that the consumer of the collection wants to clear and re-fill the collection and this implementation does not allow that.
It forces the use of IList<T> abstraction and a custom implementation over List<T>
Although this provides a real thread-safe way of removing a just emptied collection from the dictionary, there seem to be more cons than pros to it. This should only be used in a closed context where the collections inside the concurrent dictionary are exposed to the outside, and where the immediate removal of a collection when emptied, even if some other thread is accessing it at the moment, is essential.
Here is the extension method to create and add the self removing list to the dictionary:
public static class ConcurrentDictionaryExtensions
{
public static IList<TValue> AddSelfRemovingList<TKey, TValue>(this ConcurrentDictionary<TKey, IList<TValue>> dictionaryInstance, TKey key)
{
var newInstance = new SelfRemovingConcurrentList<TKey, TValue>(dictionaryInstance, key);
if (!dictionaryInstance.TryAdd(key, newInstance))
{
throw new ArgumentException("ownerAccessKey", "The passed ownerAccessKey has already exist in the parent dictionary");
}
return newInstance;
}
}
And finally; here is the synchronized, self-removing implementation of IList<T>:
public class SelfRemovingConcurrentList<TKey, TValue> : IList<TValue>
{
private ConcurrentDictionary<TKey, IList<TValue>> owner;
private TKey ownerAccessKey;
List<TValue> underlyingList = new List<TValue>();
private bool hasRemovedSelf;
public class HasAlreadyRemovedSelfException : Exception
{
}
internal SelfRemovingConcurrentList(ConcurrentDictionary<TKey, IList<TValue>> owner, TKey ownerAccessKey)
{
this.owner = owner;
this.ownerAccessKey = ownerAccessKey;
}
private void ThrowIfHasAlreadyRemovedSelf()
{
if (hasRemovedSelf)
{
throw new HasAlreadyRemovedSelfException();
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
int IList<TValue>.IndexOf(TValue item)
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList.IndexOf(item);
}
[MethodImpl(MethodImplOptions.Synchronized)]
void IList<TValue>.Insert(int index, TValue item)
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList.Insert(index, item);
}
[MethodImpl(MethodImplOptions.Synchronized)]
void IList<TValue>.RemoveAt(int index)
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList.RemoveAt(index);
if (underlyingList.Count == 0)
{
hasRemovedSelf = true;
IList<TValue> removedInstance;
if (!owner.TryRemove(ownerAccessKey, out removedInstance))
{
// Just ignore.
// What we want to do is to remove ourself from the owner (concurrent dictionary)
// and it seems like we have already been removed!
}
}
}
TValue IList<TValue>.this[int index]
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList[index];
}
[MethodImpl(MethodImplOptions.Synchronized)]
set
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList[index] = value;
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
void ICollection<TValue>.Add(TValue item)
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList.Add(item);
}
[MethodImpl(MethodImplOptions.Synchronized)]
void ICollection<TValue>.Clear()
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList.Clear();
hasRemovedSelf = true;
IList<TValue> removedInstance;
if (!owner.TryRemove(ownerAccessKey, out removedInstance))
{
// Just ignore.
// What we want to do is to remove ourself from the owner (concurrent dictionary)
// and it seems like we have already been removed!
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
bool ICollection<TValue>.Contains(TValue item)
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList.Contains(item);
}
[MethodImpl(MethodImplOptions.Synchronized)]
void ICollection<TValue>.CopyTo(TValue[] array, int arrayIndex)
{
ThrowIfHasAlreadyRemovedSelf();
underlyingList.CopyTo(array, arrayIndex);
}
int ICollection<TValue>.Count
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList.Count;
}
}
bool ICollection<TValue>.IsReadOnly
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
ThrowIfHasAlreadyRemovedSelf();
return false;
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
bool ICollection<TValue>.Remove(TValue item)
{
ThrowIfHasAlreadyRemovedSelf();
bool removalResult = underlyingList.Remove(item);
if (underlyingList.Count == 0)
{
hasRemovedSelf = true;
IList<TValue> removedInstance;
if (!owner.TryRemove(ownerAccessKey, out removedInstance))
{
// Just ignore.
// What we want to do is to remove ourself from the owner (concurrent dictionary)
// and it seems like we have already been removed!
}
}
return removalResult;
}
[MethodImpl(MethodImplOptions.Synchronized)]
IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList.GetEnumerator();
}
[MethodImpl(MethodImplOptions.Synchronized)]
IEnumerator IEnumerable.GetEnumerator()
{
ThrowIfHasAlreadyRemovedSelf();
return underlyingList.GetEnumerator();
}
}
The question can be solved by using a dictionary that offers a variant of TryRemove that first checks that the current value is equal to an expected value. Only if the values compare equal, the value is replaced (atomically). Otherwise, the operation returns failure.
It turns out ConcurrentDictionary already implements exactly this functionality:
/// <summary>
/// Removes the specified key from the dictionary if it exists and returns its associated value.
/// If matchValue flag is set, the key will be removed only if is associated with a particular
/// value.
/// </summary>
/// <param name="key">The key to search for and remove if it exists.</param>
/// <param name="value">The variable into which the removed value, if found, is stored.</param>
/// <param name="matchValue">Whether removal of the key is conditional on its value.</param>
/// <param name="oldValue">The conditional value to compare against if <paramref name="matchValue"/> is true</param>
/// <returns></returns>
private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue)
TryRemove calls this (with matchValue set to false). The method is sadly not exposed (it is private). A simple solution would thus be to copy the existing class and change this method to be public. I'm not sure why it was not exposed. If the specific functionality were not working well, matchValue would most likely have been removed earlier.
As #Theodor Zoulias notes, it is also possible to invoke the private TryRemoveInternal method by using reflection. As far as I know, this can be done without major impact on performence.
There are also third party implementations with (claimed) high performance and concurrency that exhibit a TryRemove (..., expectedValue).
Once an implementation is chosen, the following code implements the asked for functionality. It uses the atomic compare-and-swap operations provided by the dictionary in a loop until it succeeds (similar to what many concurrent dictionaries do internally, too). As far as I'm aware, this is a typical approach in lock-free algorithms.
// Use any third-party dictionary that offers TryRemove() with
// a value to compare against (two are mentioned above)
ConcurrentDictionary<TKey, List<TValue>> d;
...
// To remove a value from key:
// Loop until the compare-and-swap of either update or removal succeeded
while (true)
{
// If the key does not exist, exit
if (!d.TryGetValue (key, out var list)) {
break;
}
// Remove the value from this key's entry:
// Consider the old value immutable, copy-and-modify it instead
List<TValue> newlist;
lock (list) {
newlist = list.Where (it => it != valueToRemove).ToList ();
}
// If the value list is not empty, compare-and-update it
if (newlist.Count > 0) {
if (d.TryUpdate (key: key, newValue: newlist, expectedValue: list)) {
return;
}
}
else // The key's value list is empty - compare-and-remove the entire key
{
// Remove the key iff the associated value is still the same
if (d.TryRemove (key: key, expectedValue: list)) { // Note that list is an in-, not an out-parameter
return;
}
}
// If we reach this point, the operation failed - try again
}

ToList with Capacity?

When we do .ToList() for an IEnumerable, the list can potentially reallocate while scanning the IEnumerable because it doesn't know the size upfront. If the size is known, is there a simple way to avoid the performance penalty? Something to the effect of initializing a List with the required capacity and then copying the IEnumerable into it? Ideally something as simple as .ToList(capacity) (which doesn't exist).
In cases when the capacity is part of IEnumerable<T> that is also an ICollection<T>, the library will allocate at the correct capacity.
Here is a reference implementation of List<T>(IEnumerable<T> source), which is invoked when you call ToList():
public List(IEnumerable<T> collection) {
if (collection==null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
Contract.EndContractBlock();
ICollection<T> c = collection as ICollection<T>;
if( c != null) {
int count = c.Count;
if (count == 0) {
_items = _emptyArray;
} else {
_items = new T[count];
c.CopyTo(_items, 0);
_size = count;
}
} else {
_size = 0;
_items = _emptyArray;
// This enumerable could be empty. Let Add allocate a new array, if needed.
// Note it will also go to _defaultCapacity first, not 1, then 2, etc.
using(IEnumerator<T> en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Add(en.Current);
}
}
}
}
Note how the constructor behaves when collection implements ICollection<T>: rather than iterating the content and calling Add for each item, it allocates the internal _items array, and copies the content into it without reallocations.
In situations when the capacity is not embedded in class implementing IEnumerable<T>, you can easily define one yourself, using a combination of standard methods:
public static class ToListExtension {
public static List<T> ToList<T>(this IEnumerable<T> source, int capacity)
{
var res = new List<T>(capacity);
res.AddRange(source);
return res;
}
}

How can I implement IEnumerator<T>?

This code is not compiling, and it's throwing the following error:
The type 'TestesInterfaces.MyCollection' already contains a definition for 'Current'
But when I delete the ambiguous method, it keeps giving other errors.
Can anyone help?
public class MyCollection<T> : IEnumerator<T>
{
private T[] vector = new T[1000];
private int actualIndex;
public void Add(T elemento)
{
this.vector[vector.Length] = elemento;
}
public bool MoveNext()
{
actualIndex++;
return (vector.Length > actualIndex);
}
public void Reset()
{
actualIndex = -1;
}
void IDisposable.Dispose() { }
public Object Current
{
get
{
return Current;
}
}
public T Current
{
get
{
try
{
T element = vector[actualIndex];
return element;
}
catch (IndexOutOfRangeException e)
{
throw new InvalidOperationException(e.Message);
}
}
}
}
I think you're misunderstanding IEnumerator<T>. Typically, collections implement IEnumerable<T>, not IEnumerator<T>. You can think of them like this:
When a class implements IEnumerable<T>, it is stating "I am a collection of things that can be enumerated."
When a class implements IEnumerator<T>, it is stating "I am a thing that enumerates over something."
It is rare (and probably wrong) for a collection to implement IEnumerator<T>. By doing so, you're limiting your collection to a single enumeration. If you try to loop through the collection within a segment of code that's already looping through the collection, or if you try to loop through the collection on multiple threads simultaneously, you won't be able to do it because your collection is itself storing the state of the enumeration operation. Typically, collections (implementing IEnumerable<T>) return a separate object (implementing IEnumerator<T>) and that separate object is responsible for storing the state of the enumeration operation. Therefore, you can have any number of concurrent or nested enumerations because each enumeration operation is represented by a distinct object.
Also, in order for the foreach statement to work, the object after the in keyword, must implement IEnumerable or IEnumerable<T>. It will not work if the object only implements IEnumerator or IEnumerator<T>.
I believe this is the code you're looking for:
public class MyCollection<T> : IEnumerable<T>
{
private T[] vector = new T[1000];
private int count;
public void Add(T elemento)
{
this.vector[count++] = elemento;
}
public IEnumerator<T> GetEnumerator()
{
return vector.Take(count).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
You need to define the interface the current is implementing.
Object IEnumerator.Current
{
//
}
public T Current
{
//
}
This way your class has 2 Current properties. but you can access them both.
MyCollection<string> col = new MyCollection<string>();
var ienumeratort = col.Current; //Uses IEnumerator<T>
var ienumerator = (IEnumerator)col.Current; //uses IEnumerator
I think with C# 2.0 onwards, you have a very easy way of implementing iterator and compiler does a lot of heavy lifting behind the scene by creating state machine. It's worth looking into it. Having said that, in that case your implementation would look something below:
public class MyCollection<T>
{
private T[] vector = new T[1000];
private int actualIndex;
public void Add(T elemento)
{
this.vector[vector.Length] = elemento;
}
public IEnumerable<T> CreateEnumerable()
{
for (int index = 0; index < vector.Length; index++)
{
yield return vector[(index + actualIndex)];
}
}
}
I am not sure about the purpose of actualIndex though - but i hope you get the idea.
After proper initialization of MyCollection, below is snippet somewhat looks like from consumer perspective:
MyCollection<int> mycoll = new MyCollection<int>();
foreach (var num in mycoll.CreateEnumerable())
{
Console.WriteLine(num);
}

Is it possible to determine if an IEnumerable<T> has deffered execution pending?

I have a function that accepts an Enumerable. I need to ensure that the enumerator is evaluated, but I'd rather not create a copy of it (e.g. via ToList() or ToArray()) if it is all ready in a List or some other "frozen" collection. By Frozen I mean collections where the set of items is already established e.g. List, Array, FsharpSet, Collection etc, as opposed to linq stuff like Select() and where().
Is it possible to create a function "ForceEvaluation" that can determine if the enumerable has deffered execution pending, and then evaluate the enumerable?
public void Process(IEnumerable<Foo> foos)
{
IEnumerable<Foo> evalutedFoos = ForceEvaluation(foos)
EnterLockedMode(); // all the deferred processing needs to have been done before this line.
foreach (Foo foo in foos)
{
Bar(foo);
}
}
public IEnumerable ForceEvaluation(IEnumerable<Foo> foos)
{
if(??????)
{ return foos}
else
{return foos.ToList()}
}
}
After some more research I've realized that this is pretty much impossible in any practical sense, and would require complex code inspection of each iterator.
So I'm going to go with a variant of Mark's answer and create a white-list of known safe types and just call ToList() anything not on that is not on the white-list.
Thank you all for your help.
Edit*
After even more reflection, I've realized that this is equivalent to the halting problem. So very impossible.
Something that worked for me way :
IEnumerable<t> deffered = someArray.Where(somecondition);
if (deffered.GetType().UnderlyingSystemType.Namespace.Equals("System.Linq"))
{
//this is a deffered executin IEnumerable
}
You could try a hopeful check against IList<T> or ICollection<T>, but note that these can still be implemented lazily - but it is much rarer, and LINQ doesn't do that - it just uses iterators (not lazy collections). So:
var list = foos as IList<Foo>;
if(list != null) return list; // unchanged
return foos.ToList();
Note that this is different to the regular .ToList(), which gives you back a different list each time, to ensure nothing unexpected happens.
Most concrete collection types (including T[] and List<T>) satisfy IList<T>. I'm not familiar with the F# collections - you'd need to check that.
I would avoid it if you want to make sure it is "frozen". Both Array elements and List<> can be changed at any time (i.e. infamous "collection changed during iteration" exception). If you really need to make sure IEnumerable is evaluated AND not changing underneath your code than copy all items into your own List/Array.
There could be other reasons to try it - i.e. some operations inside run time do special checks for collection being an array to optimize them. Or have special version for specialized interface like ICollection or IQueryable in addition to generic IEnumerable.
EDIT: Example of collection changing during iteration:
IEnumerable<T> collectionAsEnumrable = collection;
foreach(var i in collectionAsEnumrable)
{
// something like following can be indirectly called by
// synchronous method on the same thread
collection.Add(i.Clone());
collection[3] = 33;
}
If it is possible to use a wrapper in your case, you could do something like this
public class ForceableEnumerable<T> : IEnumerable<T>
{
IEnumerable<T> _enumerable;
IEnumerator<T> _enumerator;
public ForceableEnumerable(IEnumerable<T> enumerable)
{
_enumerable = enumerable;
}
public void ForceEvaluation()
{
if (_enumerator != null) {
while (_enumerator.MoveNext()) {
}
}
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
_enumerator = _enumerable.GetEnumerator();
return _enumerator;
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
Or implement the force method like this if you want to evaluate in any case
public void ForceEvaluation()
{
if (_enumerator == null) {
_enumerator = _enumerable.GetEnumerator();
}
while (_enumerator.MoveNext()) {
}
}
EDIT:
If you want to ensure that the enumeration is evaluated only once in any case, you could change GetEnumerator to
public IEnumerator<T> GetEnumerator()
{
if (_enumerator == null) }
_enumerator = _enumerable.GetEnumerator();
}
return _enumerator;
}

simulate List like hashSet in C# so that List will have noduplicate values

I want to add colections to List, but only if Advertisements does not already exist in it. I know that HashSet works like this that has no duplicate values, but with HashSet i can not use AddRange and GetRange.
So is it possible to simulate List like hashSet?
List<Advertisements> advertisements = new List<Advertisements>();
advertisements.AddRange(NHibernateSession.CreateCriteria<Advertisements>()
.CreateCriteria(AdvertisementsProperties.City.ToString())
.Add(Restrictions.Or(
Restrictions.Like(CitiesProperties.Name.ToString(), text, MatchMode.Anywhere),
Restrictions.Like(CitiesProperties.SlovenianName.ToString(), text, MatchMode.Anywhere)))
.List<Advertisements>());
advertisements.AddRange(NHibernateSession.CreateCriteria<Advertisements>()
.CreateCriteria(AdvertisementsProperties.Area.ToString())
.Add(Restrictions.Or(
Restrictions.Like(AreasProperties.Name.ToString(), text, MatchMode.Anywhere),
Restrictions.Like(AreasProperties.SlovenianName.ToString(), text, MatchMode.Anywhere)))
.List<Advertisements>());
To add a bunch of items to a HashSet like AddRange does simply use:
set.UnionWith(items);
The items in a HashSet are not indexed (it's implemented as a hash table which is not designed for index based access to elements). If you strictly need to store items by index, you'll have to use a simple list and create your own Add method that checks Contains on each element before adding it to the underlying list. Of course, a linear list doesn't provide the efficiency of set operations as HashSet does.
Check out this post. The poster used an extension method to add "AddRange" functionality to HashSet.
You'd probably want to create your own class if you often need a hybrid List/Set collection functionality. It would go something like this:
using System;
using System.Collections;
using System.Collections.Generic;
public class ListSet<T> : IList<T>, ISet<T> // ISet<T> is supported only from .NET 4.0 on
{
#region Inner collections
private HashSet<T> _innerSet = new HashSet<T>();
private List<T> _innerList = new List<T>();
#endregion
#region The read methods delegate to the inner collection which is more appropriate and efficient:
public bool Contains(T item)
{
return this._innerSet.Contains(item);
}
public int IndexOf(T item)
{
return this._innerList.IndexOf(item);
}
// TODO: Implement all other read operations
#endregion
#region The write methods must keep both inner collections synchronized
public bool Add(T item)
{
bool wasAdded = this._innerSet.Add(item);
if (wasAdded) this._innerList.Add(item);
return wasAdded;
}
public void AddRange(IEnumerable<T> items)
{
foreach (T item in items) this.Add(item);
}
public bool Remove(T item)
{
if (this._innerSet.Remove(item))
{
return this._innerList.Remove(item);
}
return false;
}
// TODO: Implement all other write operations
// TODO: Consider implementing roll back mechanisms in exception handlers
// when write operations fail
#endregion
}

Categories