#region Copyright 2011-2014 by Roger Knapp, Licensed under the Apache License, Version 2.0
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System.Collections.Generic;
using CSharpTest.Net.Synchronization;
namespace CSharpTest.Net.Collections
{
///
/// Represents a collection of objects that can be individually accessed by index.
///
public class SynchronizedList : IList
{
IList _store;
readonly ILockStrategy _lock;
///
/// Constructs a thread-safe generic collection of key/value pairs using exclusive locking.
///
public SynchronizedList()
: this(new List(), new ExclusiveLocking())
{ }
///
/// Constructs a thread-safe generic collection of key/value pairs using the lock provided.
///
public SynchronizedList(ILockStrategy locking)
: this(new List(), locking)
{ }
///
/// Constructs a thread-safe generic collection of T, wrapped around the instance in storage
/// using the default locking type for exclusive access, akin to placing lock(this) around
/// each call. If you want to allow reader/writer locking provide one of those lock types
/// from the Synchronization namespace.
///
public SynchronizedList(IList storage)
: this(storage, new ExclusiveLocking())
{ }
///
/// Constructs a thread-safe generic collection of T, wrapped around the instance in storage
///
public SynchronizedList(IList storage, ILockStrategy locking)
{
_store = Check.NotNull(storage);
_lock = Check.NotNull(locking);
}
///
/// Defines a method to release allocated resources.
///
public void Dispose()
{
_lock.Dispose();
}
/// Exposes the interal lock so that you can syncronize several calls
public ILockStrategy Lock { get { return _lock; } }
///
/// Gets a value indicating whether the is read-only.
///
public bool IsReadOnly { get { return _store.IsReadOnly; } }
///
/// Gets the number of elements contained in the .
///
public int Count { get { using (_lock.Read()) return _store.Count; } }
///
/// Locks the collection and replaces the underlying storage dictionary.
///
public IList ReplaceStorage(IList newStorage)
{
using (_lock.Write())
{
IList storage = _store;
_store = Check.NotNull(newStorage);
return storage;
}
}
///
/// Gets or sets the element at the specified index.
///
public T this[int index]
{
get
{
using (_lock.Read())
return _store[index];
}
set
{
using (_lock.Write())
_store[index] = value;
}
}
///
/// Adds an item to the .
///
public int Add(T item)
{
using (_lock.Write())
{
_store.Add(item);
return _store.Count - 1;
}
}
///
/// Added the public version to return the ordinal since you cannot depend upon the collection being
/// unmodified to determine the index either before or after the Add() call.
///
void ICollection.Add(T item)
{
using (_lock.Write())
_store.Add(item);
}
///
/// Inserts an item to the at the specified index.
///
public void Insert(int index, T item)
{
using (_lock.Write())
_store.Insert(index, item);
}
///
/// Removes the first occurrence of a specific object from the .
///
public bool Remove(T item)
{
using (_lock.Write())
return _store.Remove(item);
}
///
/// Removes the item at the specified index.
///
public void RemoveAt(int index)
{
using (_lock.Write())
_store.RemoveAt(index);
}
///
/// Removes all items from the .
///
public void Clear()
{
using (_lock.Write())
_store.Clear();
}
///
/// Determines whether the contains the element specified.
///
public bool Contains(T item)
{
using (_lock.Read())
return _store.Contains(item);
}
///
/// Determines the index of a specific item in the .
///
public int IndexOf(T item)
{
using (_lock.Read())
return _store.IndexOf(item);
}
///
/// Copies the elements of the to an , starting at a particular index.
///
public void CopyTo(T[] array, int arrayIndex)
{
using (_lock.Read())
_store.CopyTo(array, arrayIndex);
}
///
/// Returns an enumerator that iterates through the collection.
///
public IEnumerator GetEnumerator()
{
using (_lock.Read())
{
foreach (T value in _store)
yield return value;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{ return GetEnumerator(); }
}
}