We use a custom collection called KeySet<T> for a dictionary of keys
only since this scenario comes up a lot. It's made programming these
things a lot easier to read and maintain.
Watch the line wrapping...
HTH,
Sam
------------------------------------------------------------
We're hiring! B-Line Medical is seeking .NET
Developers for exciting positions in medical product
development in MD/DC. Work with a variety of technologies
in a relaxed team environment. See ads on Dice.com.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Common
{
/// <summary>
/// Provides a collection of unordered unique keys.
/// </summary>
/// <typeparam name="T">The type of keys to collection</typeparam>
/// <remarks>
/// KeySet is similar to a Dictionary but does not contain a value
and is useful when one only cares about existence of
/// keys and not values associated with them.
/// </remarks>
[DebuggerStepThrough]
public class KeySet<T> : IDictionary<T, bool>, ICollection<T>,
IEnumerable<T>, ICollection
{
#region Data
private Dictionary<T, bool> _dictionary;
#endregion
#region Constructors
public KeySet() : this(0)
{
}
public KeySet(IEqualityComparer<T> comparer) : this(0, comparer)
{
}
public KeySet(int capactity)
: this(capactity, null)
{
}
public KeySet(int capactity, IEqualityComparer<T> comparer)
{
_dictionary = new Dictionary<T, bool>(capactity, comparer);
}
public KeySet(ICollection<T> collection) : this(collection, null)
{
}
public KeySet(ICollection<T> collection, IEqualityComparer<T>
comparer)
{
if (collection == null)
{
throw new ArgumentNullException("collection");
}
_dictionary = new Dictionary<T, bool>(collection.Count,
comparer);
foreach (T key in collection)
{
_dictionary[key] = true;
}
}
#endregion
#region Public Properties
public int Count
{
get
{
return _dictionary.Count;
}
}
public ICollection<T> Keys
{
get
{
return _dictionary.Keys;
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
/// <summary>
/// Returns true if the key exists in the collection, false
otherwise.
/// </summary>
/// <param name="key">Key to check for.</param>
/// <returns>True if key exists in collection.</returns>
/// <remarks>
/// Setting a value to false will remove the key from the
collection if it exists.
///
/// Unlike IDictionary<>> the indexer will not throw an
exception on an non-existent key, it will simply return false.
/// </remarks>
public bool this[T key]
{
get
{
return _dictionary.ContainsKey(key);
}
set
{
if (value)
{
_dictionary[key] = true;
}
else
{
_dictionary.Remove(key);
}
}
}
#endregion
#region Public Methods
public void Add(T key)
{
_dictionary.Add(key, true);
}
public void Add(ICollection<T> collection)
{
if (collection == null)
{
throw new ArgumentNullException("collection");
}
foreach(T key in collection)
{
_dictionary.Add(key, true);
}
}
///<summary>
///Removes all items from the <see
cref="T:System.Collections.Generic.ICollection`1"></see>.
///</summary>
///
///<exception cref="T:System.NotSupportedException">The <see
cref="T:System.Collections.Generic.ICollection`1"></see> is read-only.
</exception>
public void Clear()
{
_dictionary.Clear();
}
public bool Contains(T key)
{
return _dictionary.ContainsKey(key);
}
public void CopyTo(T[] array, int arrayIndex)
{
_dictionary.Keys.CopyTo(array, arrayIndex);
}
public IEnumerator<T> GetEnumerator()
{
return _dictionary.Keys.GetEnumerator();
}
public bool Remove(T key)
{
return _dictionary.Remove(key);
}
public bool TryGetValue(T key, out bool value)
{
return _dictionary.TryGetValue(key, out value);
}
#endregion
#region IDictionary<T,bool> Members
///<summary>
///Adds an element with the provided key and value to the <see
cref="T:System.Collections.Generic.IDictionary`2"></see>.
///</summary>
///
///<param name="value">The bool to use as the value of the element
to add.</param>
///<param name="key">The bool to use as the key of the element to
add.</param>
///<exception cref="T:System.NotSupportedException">The <see
cref="T:System.Collections.Generic.IDictionary`2"></see> is
read-only.</exception>
///<exception cref="T:System.ArgumentException">An element with
the same key already exists in the <see
cref="T:System.Collections.Generic.IDictionary`2"></see>.</exception>
///<exception cref="T:System.ArgumentNullException">key is
null.</exception>
void IDictionary<T, bool>.Add(T key, bool value)
{
if (!value)
{
throw TrueOnlyException;
}
_dictionary.Add(key, true);
}
///<summary>
///Determines whether the <see
cref="T:System.Collections.Generic.IDictionary`2"></see> contains an
element with the specified key.
///</summary>
///
///<returns>
///true if the <see
cref="T:System.Collections.Generic.IDictionary`2"></see> contains an
element with the key; otherwise, false.
///</returns>
///
///<param name="key">The key to locate in the <see
cref="T:System.Collections.Generic.IDictionary`2"></see>.</param>
///<exception cref="T:System.ArgumentNullException">key is
null.</exception>
bool IDictionary<T, bool>.ContainsKey(T key)
{
return _dictionary.ContainsKey(key);
}
///<summary>
///Gets an <see
cref="T:System.Collections.Generic.ICollection`1"></see> containing
the values in the <see
cref="T:System.Collections.Generic.IDictionary`2"></see>.
///</summary>
///
///<returns>
///An <see
cref="T:System.Collections.Generic.ICollection`1"></see> containing
the values in the bool that implements <see
cref="T:System.Collections.Generic.IDictionary`2"></see>.
///</returns>
///
ICollection<bool> IDictionary<T, bool>.Values
{
get
{
return _dictionary.Values;
}
}
#endregion
#region ICollection<KeyValuePair<T,bool>> Members
///<summary>
///Removes the first occurrence of a specific bool from the <see
cref="T:System.Collections.Generic.ICollection`1"></see>.
///</summary>
///
///<returns>
///true if item was successfully removed from the <see
cref="T:System.Collections.Generic.ICollection`1"></see>; otherwise,
false. This method also returns false if item is not found in the
original <see
cref="T:System.Collections.Generic.ICollection`1"></see>.
///</returns>
///
///<param name="item">The bool to remove from the <see
cref="T:System.Collections.Generic.ICollection`1"></see>.</param>
///<exception cref="T:System.NotSupportedException">The <see
cref="T:System.Collections.Generic.ICollection`1"></see> is
read-only.</exception>
bool ICollection<KeyValuePair<T, bool>>.Remove(KeyValuePair<T,
bool> item)
{
return _dictionary.Remove(item.Key);
}
///<summary>
///Copies the elements of the <see
cref="T:System.Collections.Generic.ICollection`1"></see> to an <see
cref="T:System.Array"></see>, starting at a particular <see
cref="T:System.Array"></see> index.
///</summary>
///
///<param name="array">The one-dimensional <see
cref="T:System.Array"></see> that is the destination of the elements
copied from <see
cref="T:System.Collections.Generic.ICollection`1"></see>. The <see
cref="T:System.Array"></see> must have zero-based indexing.</param>
///<param name="arrayIndex">The zero-based index in array at which
copying begins.</param>
///<exception
cref="T:System.ArgumentOutOfRangeException">arrayIndex is less than
0.</exception>
///<exception cref="T:System.ArgumentNullException">array is
null.</exception>
///<exception cref="T:System.ArgumentException">array is
multidimensional.-or-arrayIndex is equal to or greater than the length
of array.-or-The number of elements in the source <see
cref="T:System.Collections.Generic.ICollection`1"></see> is greater
than the available space from arrayIndex to the end of the destination
array.-or-Type T cannot be cast automatically to the type of the
destination array.</exception>
void ICollection<KeyValuePair<T, bool>>.CopyTo(KeyValuePair<T,
bool>[] array, int arrayIndex)
{
((ICollection<KeyValuePair<T, bool>>) _dictionary).CopyTo(array,
arrayIndex);
}
///<summary>
///Determines whether the <see
cref="T:System.Collections.Generic.ICollection`1"></see> contains a
specific value.
///</summary>
///
///<returns>
///true if item is found in the <see
cref="T:System.Collections.Generic.ICollection`1"></see>; otherwise,
false.
///</returns>
///
///<param name="item">The bool to locate in the <see
cref="T:System.Collections.Generic.ICollection`1"></see>.</param>
bool ICollection<KeyValuePair<T, bool>>.Contains(KeyValuePair<T,
bool> item)
{
return _dictionary.ContainsKey(item.Key);
}
///<summary>
///Adds an item to the <see
cref="T:System.Collections.Generic.ICollection`1"></see>.
///</summary>
///
///<param name="item">The bool to add to the <see
cref="T:System.Collections.Generic.ICollection`1"></see>.</param>
///<exception cref="T:System.NotSupportedException">The <see
cref="T:System.Collections.Generic.ICollection`1"></see> is
read-only.</exception>
void ICollection<KeyValuePair<T, bool>>.Add(KeyValuePair<T, bool>
item)
{
if (item.Value)
{
throw TrueOnlyException;
}
_dictionary.Add(item.Key, true);
}
#endregion
#region ICollection Members
///<summary>
///Copies the elements of the <see
cref="T:System.Collections.ICollection"></see> to an <see
cref="T:System.Array"></see>, starting at a particular <see
cref="T:System.Array"></see> index.
///</summary>
///
///<param name="array">The one-dimensional <see
cref="T:System.Array"></see> that is the destination of the elements
copied from <see cref="T:System.Collections.ICollection"></see>. The
<see cref="T:System.Array"></see> must have zero-based indexing.
</param>
///<param name="index">The zero-based index in array at which
copying begins. </param>
///<exception cref="T:System.ArgumentNullException">array is null.
</exception>
///<exception cref="T:System.ArgumentOutOfRangeException">index is
less than zero. </exception>
///<exception cref="T:System.ArgumentException">array is
multidimensional.-or- index is equal to or greater than the length of
array.-or- The number of elements in the source <see
cref="T:System.Collections.ICollection"></see> is greater than the
available space from index to the end of the destination array.
</exception>
///<exception cref="T:System.InvalidCastException">The type of the
source <see cref="T:System.Collections.ICollection"></see> cannot be
cast automatically to the type of the destination array.
</exception><filterpriority>2</filterpriority>
void ICollection.CopyTo(Array array, int index)
{
((IDictionary) _dictionary).Keys.CopyTo(array, index);
}
///<summary>
///Gets an object that can be used to synchronize access to the
<see cref="T:System.Collections.ICollection"></see>.
///</summary>
///
///<returns>
///An object that can be used to synchronize access to the <see
cref="T:System.Collections.ICollection"></see>.
///</returns>
///<filterpriority>2</filterpriority>
object ICollection.SyncRoot
{
get
{
return ((ICollection) _dictionary).SyncRoot;
}
}
///<summary>
///Gets a value indicating whether access to the <see
cref="T:System.Collections.ICollection"></see> is synchronized (thread
safe).
///</summary>
///
///<returns>
///true if access to the <see
cref="T:System.Collections.ICollection"></see> is synchronized (thread
safe); otherwise, false.
///</returns>
///<filterpriority>2</filterpriority>
bool ICollection.IsSynchronized
{
get
{
return ((ICollection)_dictionary).IsSynchronized;
}
}
#endregion
#region IEnumerable<KeyValuePair<T,bool>> Members
///<summary>
///Returns an enumerator that iterates through the collection.
///</summary>
///
///<returns>
///A <see cref="T:System.Collections.Generic.IEnumerator`1"></see>
that can be used to iterate through the collection.
///</returns>
///<filterpriority>1</filterpriority>
IEnumerator<KeyValuePair<T, bool>> IEnumerable<KeyValuePair<T,
bool>>.GetEnumerator()
{
return ((IEnumerable<KeyValuePair<T, bool>>)
_dictionary).GetEnumerator();
}
#endregion
#region IEnumerable Members
///<summary>
///Returns an enumerator that iterates through a collection.
///</summary>
///
///<returns>
///An <see cref="T:System.Collections.IEnumerator"></see> bool
that can be used to iterate through the collection.
///</returns>
///<filterpriority>2</filterpriority>
IEnumerator IEnumerable.GetEnumerator()
{
return _dictionary.Keys.GetEnumerator();
}
#endregion
#region Private Helpers
private static ArgumentException TrueOnlyException
{
get
{
return new ArgumentException("KeySet only supports 'true'
values.");
}
}
#endregion
}
}