Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Wednesday, December 22, 2010 9:15 AM
Hi,
I am supporting a legacy C# application.
I sometimes see code as follows in the application:
IDictionary<string, string> dict = new Dictionary<string, string>();
What is the benefit of this declaration over
Dictionary<string, string> dict = new Dictionary<string, string>();
Thanks
All replies (7)
Thursday, December 23, 2010 4:16 AM âś…Answered
Thanks for all the responses.
I think the fact that IDictionary enables looser coupling is probably why it was implemented in this way.
There's not really any benefit to the implementation you see... as per .Net polymorphism rules, an instantiated Dictionary class can be passed to IDictionary AND Dictionary typed parameters, because Dictionary implements IDictionary.
However, you cannot pass an instantiated IDictionary to a Dictionary parameter, as the Dictionary parameter expects a strongly typed Dictionary object. If you pass an IDictionary through, it won't contain all the signatures in the Dictionary object, so it will break the compiler. Here's a quick extension to my Test class above:
public class Test {
public Test() {
IMyInterface i = new MyClass();
i.BaseMethod();
i.ChildMethod(); // Breaks compiler as ChildMethod() is not available to IMyInterface
MyClass c = new MyClass();
c.BaseMethod();
c.ChildMethod(); // Works fine.
testing(i); // Breaks
testing(c); // Works
}
public void testing(MyClass test) {
Debug.WriteLine("Only accepts MyClass parameters.");
}
//public void testing(IMyInterface test) {
// Debug.WriteLine("Accepts MyClass and IMyInterface parameters");
//}
}
If you copy + paste that in to Visual studio (along with the class and interface definitions above), you will see the underlined compiler errors. If you comment out the last method stub (the overloaded "testing" method), the error on the testing(i); line will go away, as a method exists that can accept the IMyInterface definition.
So, in summary - if you instantiate a Dictionary object in to an IDictionary interface, you are LOOSING data and functionality, not enhancing it. In my experience there is no benefit to this whatsoever, unless you fully intend to lose the additional information for a reason.
My advice - change it to Dictionary.
Wednesday, December 22, 2010 9:33 AM
IDictionary is an interface - i.e. you cannot instantiate it and it provides base-level member signatures, but no implementation for the members (no code in the members).
Your first line will only give you access to the IDictionary members (i.e. if there are any additional members in the Dictionary class, they won't be copied over to the new dict variable.
The second line will give you access to all members of the Dictionary class.
Dictionary implements IDictionary - therefore Dictionary is likely to contain more members than IDictionary.
I'll do some testing and post some examples in a minute...
Wednesday, December 22, 2010 9:35 AM
IDictionary enables looser coupling.
Let's say you have a method:
void KillJavaProgrammers(IDictionary<string, string> d)
{
// loop over all programmers, and hang those using java
}
You are free to use it in various ways:
Dictionary<string, string> programmers = new Dictionary<string, string>();
SortedDictionary<string, string> coders = new SortedDictionary<string, string>();
KillJavaProgrammers(programmers);
KillJavaProgrammers(coders);
PS: Sorry, the pommie and me was answering at the same time. Hope either one help clear things up.
Wednesday, December 22, 2010 9:43 AM
FYI, you can see the signatures of each of the objects (in the metadata) by having the system carat (your cursor) over the class name, then pressing F12.
public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback {
// Summary:
// Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
// class that is empty, has the default initial capacity, and uses the default
// equality comparer for the key type.
public Dictionary();
//
// Summary:
// Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
// class that contains elements copied from the specified System.Collections.Generic.IDictionary<TKey,TValue>
// and uses the default equality comparer for the key type.
//
// Parameters:
// dictionary:
// The System.Collections.Generic.IDictionary<TKey,TValue> whose elements are
// copied to the new System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Exceptions:
// System.ArgumentNullException:
// dictionary is null.
//
// System.ArgumentException:
// dictionary contains one or more duplicate keys.
public Dictionary(IDictionary<TKey, TValue> dictionary);
//
// Summary:
// Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
// class that is empty, has the default initial capacity, and uses the specified
// System.Collections.Generic.IEqualityComparer<T>.
//
// Parameters:
// comparer:
// The System.Collections.Generic.IEqualityComparer<T> implementation to use
// when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer<T>
// for the type of the key.
public Dictionary(IEqualityComparer<TKey> comparer);
//
// Summary:
// Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
// class that is empty, has the specified initial capacity, and uses the default
// equality comparer for the key type.
//
// Parameters:
// capacity:
// The initial number of elements that the System.Collections.Generic.Dictionary<TKey,TValue>
// can contain.
//
// Exceptions:
// System.ArgumentOutOfRangeException:
// capacity is less than 0.
public Dictionary(int capacity);
//
// Summary:
// Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
// class that contains elements copied from the specified System.Collections.Generic.IDictionary<TKey,TValue>
// and uses the specified System.Collections.Generic.IEqualityComparer<T>.
//
// Parameters:
// dictionary:
// The System.Collections.Generic.IDictionary<TKey,TValue> whose elements are
// copied to the new System.Collections.Generic.Dictionary<TKey,TValue>.
//
// comparer:
// The System.Collections.Generic.IEqualityComparer<T> implementation to use
// when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer<T>
// for the type of the key.
//
// Exceptions:
// System.ArgumentNullException:
// dictionary is null.
//
// System.ArgumentException:
// dictionary contains one or more duplicate keys.
public Dictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer);
//
// Summary:
// Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
// class that is empty, has the specified initial capacity, and uses the specified
// System.Collections.Generic.IEqualityComparer<T>.
//
// Parameters:
// capacity:
// The initial number of elements that the System.Collections.Generic.Dictionary<TKey,TValue>
// can contain.
//
// comparer:
// The System.Collections.Generic.IEqualityComparer<T> implementation to use
// when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer<T>
// for the type of the key.
//
// Exceptions:
// System.ArgumentOutOfRangeException:
// capacity is less than 0.
public Dictionary(int capacity, IEqualityComparer<TKey> comparer);
//
// Summary:
// Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>
// class with serialized data.
//
// Parameters:
// info:
// A System.Runtime.Serialization.SerializationInfo object containing the information
// required to serialize the System.Collections.Generic.Dictionary<TKey,TValue>.
//
// context:
// A System.Runtime.Serialization.StreamingContext structure containing the
// source and destination of the serialized stream associated with the System.Collections.Generic.Dictionary<TKey,TValue>.
protected Dictionary(SerializationInfo info, StreamingContext context);
// Summary:
// Gets the System.Collections.Generic.IEqualityComparer<T> that is used to
// determine equality of keys for the dictionary.
//
// Returns:
// The System.Collections.Generic.IEqualityComparer<T> generic interface implementation
// that is used to determine equality of keys for the current System.Collections.Generic.Dictionary<TKey,TValue>
// and to provide hash values for the keys.
public IEqualityComparer<TKey> Comparer { get; }
//
// Summary:
// Gets the number of key/value pairs contained in the System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Returns:
// The number of key/value pairs contained in the System.Collections.Generic.Dictionary<TKey,TValue>.
public int Count { get; }
//
// Summary:
// Gets a collection containing the keys in the System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Returns:
// A System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection containing
// the keys in the System.Collections.Generic.Dictionary<TKey,TValue>.
public Dictionary<TKey, TValue>.KeyCollection Keys { get; }
//
// Summary:
// Gets a collection containing the values in the System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Returns:
// A System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection containing
// the values in the System.Collections.Generic.Dictionary<TKey,TValue>.
public Dictionary<TKey, TValue>.ValueCollection Values { get; }
// Summary:
// Gets or sets the value associated with the specified key.
//
// Parameters:
// key:
// The key of the value to get or set.
//
// Returns:
// The value associated with the specified key. If the specified key is not
// found, a get operation throws a System.Collections.Generic.KeyNotFoundException,
// and a set operation creates a new element with the specified key.
//
// Exceptions:
// System.ArgumentNullException:
// key is null.
//
// System.Collections.Generic.KeyNotFoundException:
// The property is retrieved and key does not exist in the collection.
public TValue this[TKey key] { get; set; }
// Summary:
// Adds the specified key and value to the dictionary.
//
// Parameters:
// key:
// The key of the element to add.
//
// value:
// The value of the element to add. The value can be null for reference types.
//
// Exceptions:
// System.ArgumentNullException:
// key is null.
//
// System.ArgumentException:
// An element with the same key already exists in the System.Collections.Generic.Dictionary<TKey,TValue>.
public void Add(TKey key, TValue value);
//
// Summary:
// Removes all keys and values from the System.Collections.Generic.Dictionary<TKey,TValue>.
public void Clear();
//
// Summary:
// Determines whether the System.Collections.Generic.Dictionary<TKey,TValue>
// contains the specified key.
//
// Parameters:
// key:
// The key to locate in the System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Returns:
// true if the System.Collections.Generic.Dictionary<TKey,TValue> contains an
// element with the specified key; otherwise, false.
//
// Exceptions:
// System.ArgumentNullException:
// key is null.
public bool ContainsKey(TKey key);
//
// Summary:
// Determines whether the System.Collections.Generic.Dictionary<TKey,TValue>
// contains a specific value.
//
// Parameters:
// value:
// The value to locate in the System.Collections.Generic.Dictionary<TKey,TValue>.
// The value can be null for reference types.
//
// Returns:
// true if the System.Collections.Generic.Dictionary<TKey,TValue> contains an
// element with the specified value; otherwise, false.
public bool ContainsValue(TValue value);
//
// Summary:
// Returns an enumerator that iterates through the System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Returns:
// A System.Collections.Generic.Dictionary<TKey,TValue>.Enumerator structure
// for the System.Collections.Generic.Dictionary<TKey,TValue>.
public Dictionary<TKey, TValue>.Enumerator GetEnumerator();
//
// Summary:
// Implements the System.Runtime.Serialization.ISerializable interface and returns
// the data needed to serialize the System.Collections.Generic.Dictionary<TKey,TValue>
// instance.
//
// Parameters:
// info:
// A System.Runtime.Serialization.SerializationInfo object that contains the
// information required to serialize the System.Collections.Generic.Dictionary<TKey,TValue>
// instance.
//
// context:
// A System.Runtime.Serialization.StreamingContext structure that contains the
// source and destination of the serialized stream associated with the System.Collections.Generic.Dictionary<TKey,TValue>
// instance.
//
// Exceptions:
// System.ArgumentNullException:
// info is null.
[SecurityCritical]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context);
//
// Summary:
// Implements the System.Runtime.Serialization.ISerializable interface and raises
// the deserialization event when the deserialization is complete.
//
// Parameters:
// sender:
// The source of the deserialization event.
//
// Exceptions:
// System.Runtime.Serialization.SerializationException:
// The System.Runtime.Serialization.SerializationInfo object associated with
// the current System.Collections.Generic.Dictionary<TKey,TValue> instance is
// invalid.
public virtual void OnDeserialization(object sender);
//
// Summary:
// Removes the value with the specified key from the System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Parameters:
// key:
// The key of the element to remove.
//
// Returns:
// true if the element is successfully found and removed; otherwise, false.
// This method returns false if key is not found in the System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Exceptions:
// System.ArgumentNullException:
// key is null.
public bool Remove(TKey key);
//
// Summary:
// Gets the value associated with the specified key.
//
// Parameters:
// key:
// The key of the value to get.
//
// value:
// When this method returns, contains the value associated with the specified
// key, if the key is found; otherwise, the default value for the type of the
// value parameter. This parameter is passed uninitialized.
//
// Returns:
// true if the System.Collections.Generic.Dictionary<TKey,TValue> contains an
// element with the specified key; otherwise, false.
//
// Exceptions:
// System.ArgumentNullException:
// key is null.
public bool TryGetValue(TKey key, out TValue value);
// Summary:
// Represents the collection of keys in a System.Collections.Generic.Dictionary<TKey,TValue>.
// This class cannot be inherited.
[Serializable]
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(Mscorlib_DictionaryKeyCollectionDebugView<,>))]
public sealed class KeyCollection : ICollection<TKey>, IEnumerable<TKey>, ICollection, IEnumerable {
// Summary:
// Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection
// class that reflects the keys in the specified System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Parameters:
// dictionary:
// The System.Collections.Generic.Dictionary<TKey,TValue> whose keys are reflected
// in the new System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection.
//
// Exceptions:
// System.ArgumentNullException:
// dictionary is null.
public KeyCollection(Dictionary<TKey, TValue> dictionary);
// Summary:
// Gets the number of elements contained in the System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection.
//
// Returns:
// The number of elements contained in the System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection.Retrieving
// the value of this property is an O(1) operation.
public int Count { get; }
// Summary:
// Copies the System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection
// elements to an existing one-dimensional System.Array, starting at the specified
// array index.
//
// Parameters:
// array:
// The one-dimensional System.Array that is the destination of the elements
// copied from System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection.
// The System.Array must have zero-based indexing.
//
// index:
// The zero-based index in array at which copying begins.
//
// Exceptions:
// System.ArgumentNullException:
// array is null.
//
// System.ArgumentOutOfRangeException:
// index is less than zero.
//
// System.ArgumentException:
// The number of elements in the source System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection
// is greater than the available space from index to the end of the destination
// array.
public void CopyTo(TKey[] array, int index);
//
// Summary:
// Returns an enumerator that iterates through the System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection.
//
// Returns:
// A System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection.Enumerator
// for the System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection.
public Dictionary<TKey, TValue>.KeyCollection.Enumerator GetEnumerator();
// Summary:
// Enumerates the elements of a System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection.
[Serializable]
public struct Enumerator : IEnumerator<TKey>, IDisposable, IEnumerator {
// Summary:
// Gets the element at the current position of the enumerator.
//
// Returns:
// The element in the System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection
// at the current position of the enumerator.
public TKey Current { get; }
// Summary:
// Releases all resources used by the System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection.Enumerator.
public void Dispose();
//
// Summary:
// Advances the enumerator to the next element of the System.Collections.Generic.Dictionary<TKey,TValue>.KeyCollection.
//
// Returns:
// true if the enumerator was successfully advanced to the next element; false
// if the enumerator has passed the end of the collection.
//
// Exceptions:
// System.InvalidOperationException:
// The collection was modified after the enumerator was created.
public bool MoveNext();
}
}
// Summary:
// Represents the collection of values in a System.Collections.Generic.Dictionary<TKey,TValue>.
// This class cannot be inherited.
[Serializable]
[DebuggerTypeProxy(typeof(Mscorlib_DictionaryValueCollectionDebugView<,>))]
[DebuggerDisplay("Count = {Count}")]
public sealed class ValueCollection : ICollection<TValue>, IEnumerable<TValue>, ICollection, IEnumerable {
// Summary:
// Initializes a new instance of the System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection
// class that reflects the values in the specified System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Parameters:
// dictionary:
// The System.Collections.Generic.Dictionary<TKey,TValue> whose values are reflected
// in the new System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection.
//
// Exceptions:
// System.ArgumentNullException:
// dictionary is null.
public ValueCollection(Dictionary<TKey, TValue> dictionary);
// Summary:
// Gets the number of elements contained in the System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection.
//
// Returns:
// The number of elements contained in the System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection.
public int Count { get; }
// Summary:
// Copies the System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection
// elements to an existing one-dimensional System.Array, starting at the specified
// array index.
//
// Parameters:
// array:
// The one-dimensional System.Array that is the destination of the elements
// copied from System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection.
// The System.Array must have zero-based indexing.
//
// index:
// The zero-based index in array at which copying begins.
//
// Exceptions:
// System.ArgumentNullException:
// array is null.
//
// System.ArgumentOutOfRangeException:
// index is less than zero.
//
// System.ArgumentException:
// The number of elements in the source System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection
// is greater than the available space from index to the end of the destination
// array.
public void CopyTo(TValue[] array, int index);
//
// Summary:
// Returns an enumerator that iterates through the System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection.
//
// Returns:
// A System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection.Enumerator
// for the System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection.
public Dictionary<TKey, TValue>.ValueCollection.Enumerator GetEnumerator();
// Summary:
// Enumerates the elements of a System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection.
[Serializable]
public struct Enumerator : IEnumerator<TValue>, IDisposable, IEnumerator {
// Summary:
// Gets the element at the current position of the enumerator.
//
// Returns:
// The element in the System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection
// at the current position of the enumerator.
public TValue Current { get; }
// Summary:
// Releases all resources used by the System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection.Enumerator.
public void Dispose();
//
// Summary:
// Advances the enumerator to the next element of the System.Collections.Generic.Dictionary<TKey,TValue>.ValueCollection.
//
// Returns:
// true if the enumerator was successfully advanced to the next element; false
// if the enumerator has passed the end of the collection.
//
// Exceptions:
// System.InvalidOperationException:
// The collection was modified after the enumerator was created.
public bool MoveNext();
}
}
// Summary:
// Enumerates the elements of a System.Collections.Generic.Dictionary<TKey,TValue>.
[Serializable]
public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, IDictionaryEnumerator, IEnumerator {
// Summary:
// Gets the element at the current position of the enumerator.
//
// Returns:
// The element in the System.Collections.Generic.Dictionary<TKey,TValue> at
// the current position of the enumerator.
public KeyValuePair<TKey, TValue> Current { get; }
// Summary:
// Releases all resources used by the System.Collections.Generic.Dictionary<TKey,TValue>.Enumerator.
public void Dispose();
//
// Summary:
// Advances the enumerator to the next element of the System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Returns:
// true if the enumerator was successfully advanced to the next element; false
// if the enumerator has passed the end of the collection.
//
// Exceptions:
// System.InvalidOperationException:
// The collection was modified after the enumerator was created.
public bool MoveNext();
}
}
Here's a quick example of how interfaces work:
using System;
namespace CSharp.Web {
public interface IMyInterface {
void BaseMethod();
string BaseProperty { get; set; }
}
public class MyClass : IMyInterface {
#region IMyInterface Members
public void BaseMethod() {
throw new NotImplementedException();
}
public string BaseProperty {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
#endregion
public string ChildMethod() {
return "Only available when instantiating MyClass.";
}
}
public class Test {
public Test() {
IMyInterface i = new MyClass();
i.BaseMethod();
i.ChildMethod(); // Breaks compiler as ChildMethod() is not available to IMyInterface
MyClass c = new MyClass();
c.BaseMethod();
c.ChildMethod(); // Works fine.
}
}
}
Basically, the i.ChildMethod() doesn't exist, because IMyInterface doesn't contain a ChildMethod member.
The reason you are allowed to instantiate a class as an Interface is because the class implements the interface - read up on Polymorphism to fully understand it...
Wednesday, December 22, 2010 9:46 AM
There is no benefit to it that I can see.
There is a drawback in that you lose the specificity of the object you created (unless you cast it to the type of the object that it actually is).
I'm guessing you replaced the first version with the second and everything worked fine. The original developer may have been confused.
Wednesday, December 22, 2010 1:44 PM
Thanks for all the responses.
I think the fact that IDictionary enables looser coupling is probably why it was implemented in this way.
Wednesday, December 22, 2010 3:44 PM
I think the fact that IDictionary enables looser coupling is probably why it was implemented in this way.
If you've ever pulled a trailer with your car, you know that looser coupling can be a bad thing.