- Why FindAll() is not in IList? IDictionary or at least Dictionary? Are you pushing me to code for implementation?
- Why WeakReference, but no WeakDictionary (get a nice one from Nick Guerrera)? WeakList? More?
- Why ReadonlyCollection<T>, but no ReadonlyDictionary<K, V>?
- (I can live with this one) Why Array.Length, but anyCollection.Count (thank Nick Guerrera again)?
…more to follow as I recall them…
8 Comments
Victor,
I do not have an answer to all your questions, at least not for the first three. But there is explanation for the last one.
I can not remember where I read it, but seems it was from one of the Microsofters. The story is that Array is of fixed length which is determined when array is created. On the contrary collection can change size dynamically therefore we speak about current count of elements in the collection. Anyway Array explicitly implements ICollection so this can be easily abstracted out.
As for the first three items I just do not believe that Microsoft did what they did due to foolishness. You know language and library design is a tricky job and every your decision is a trade-off. I’m sure these questions can be answered if right people are asked.
Thanks Dmitry.
I’m far from considering Microsoft fools (if they were, would they be that rich?). It’s just the system complexity barrier that slows you down greatly you at some point.
Depending on software design approach, the resulting system becomes difficult to change sooner or later.
As for me, Microsoft’s commercial approach leads to somewhat suboptimal (or maybe not too mature) technical decisions. It’s products are way better then many others, but still there are samples off better decisions — do not read further unless you’d like a holywar — like maybe in Java or Smalltalk.
On more specific topic, I can also advocate Microsoft sometimes. and do so. Though, for Atrray.Length, I’d object.
There are immutable collections that can’t change not only size, but also their contents. Though, nobody complains about that.
I’m sure that if array’s length was called Count, it would be OK with everyone.
I don’t think there was a specific reason, rather “it just happened so” – another hit of system complexity barrier.
Yep, you got it right: “commercial approach leads to somewhat suboptimal (or maybe not too mature) technical decisions” and vice versa. And as usual truth is somewhere in between. Practice is always about compromises, you just have make right compromises 😉
My recent change to it…
public override bool ContainsKey(TKey key) weakValue;
{
// return this.dictionary.ContainsKey(key);
if (!this.dictionary.ContainsKey(key)) return false;
WeakReference
return (this.dictionary.TryGetValue(key, out weakValue));
}
///
/// A read only dictionary wrapper.
///
/// The type of the key.
/// The type of the value.
[Serializable]
public class ReadOnlyDictionary : IDictionary
{
#region Private Variables
private readonly IDictionary _dictionary;
#endregion
#region Protected Properties
///
/// Gets the dictionary.
///
/// The dictionary.
protected IDictionary Dictionary
{
get
{
return _dictionary;
}
}
#endregion
#region IDictionary Methods
[SuppressMessage(“Microsoft.Design”, “CA1033:InterfaceMethodsShouldBeCallableByChildTypes”)]
void IDictionary.Add(TKey key, TValue value)
{
throw ExceptionHelper.CreateNotSupportedException(MethodBase.GetCurrentMethod());
}
[SuppressMessage(“Microsoft.Design”, “CA1033:InterfaceMethodsShouldBeCallableByChildTypes”)]
bool IDictionary.Remove(TKey key)
{
throw ExceptionHelper.CreateNotSupportedException(MethodBase.GetCurrentMethod());
}
///
/// Determines whether the contains an element with the specified key.
///
/// The key to locate in the .
///
/// true if the contains an element with the key; otherwise, false.
///
///
/// is null.
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}
///
/// Gets the value associated with the specified key.
///
/// The key whose value to get.
/// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized.
///
/// true if the object that implements contains an element with the specified key; otherwise, false.
///
///
/// is null.
public bool TryGetValue(TKey key, out TValue value)
{
return _dictionary.TryGetValue(key, out value);
}
#endregion
#region Public Properties
///
/// Gets an containing the keys of the .
///
///
/// An containing the keys of the object that implements .
public ICollection Keys
{
get
{
return _dictionary.Keys;
}
}
///
/// Gets an containing the values in the .
///
///
/// An containing the values in the object that implements .
public ICollection Values
{
get
{
return _dictionary.Values;
}
}
[SuppressMessage(“Microsoft.Design”, “CA1033:InterfaceMethodsShouldBeCallableByChildTypes”)]
TValue IDictionary.this[TKey key]
{
get
{
return this[key];
}
set
{
throw ExceptionHelper.CreateNotSupportedException(MethodBase.GetCurrentMethod());
}
}
///
/// Gets the value with the specified key.
///
public TValue this[TKey key]
{
get
{
return _dictionary[key];
}
}
///
/// Gets the number of elements contained in the .
///
///
/// The number of elements contained in the .
public int Count
{
get
{
return _dictionary.Count;
}
}
///
/// Gets a value indicating whether the is read-only.
///
///
/// true if the is read-only; otherwise, false.
public bool IsReadOnly
{
get
{
return true;
}
}
#endregion
#region ICollection<KeyValuePair> Members
[SuppressMessage(“Microsoft.Design”, “CA1033:InterfaceMethodsShouldBeCallableByChildTypes”)]
void ICollection<KeyValuePair>.Add(KeyValuePair item)
{
throw ExceptionHelper.CreateNotSupportedException(MethodBase.GetCurrentMethod());
}
[SuppressMessage(“Microsoft.Design”, “CA1033:InterfaceMethodsShouldBeCallableByChildTypes”)]
void ICollection<KeyValuePair>.Clear()
{
throw ExceptionHelper.CreateNotSupportedException(MethodBase.GetCurrentMethod());
}
[SuppressMessage(“Microsoft.Design”, “CA1033:InterfaceMethodsShouldBeCallableByChildTypes”)]
bool ICollection<KeyValuePair>.Contains(KeyValuePair item)
{
return _dictionary.Contains(item);
}
[SuppressMessage(“Microsoft.Design”, “CA1033:InterfaceMethodsShouldBeCallableByChildTypes”)]
bool ICollection<KeyValuePair>.Remove(KeyValuePair item)
{
throw ExceptionHelper.CreateNotSupportedException(MethodBase.GetCurrentMethod());
}
///
/// Copies the elements of the to an , starting at a particular index.
///
/// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing.
/// The zero-based index in at which copying begins.
///
/// is null.
///
/// is less than 0.
///
/// is multidimensional.-or- is equal to or greater than the length of .-or-The number of elements in the source is greater than the available space from to the end of the destination .-or-Type cannot be cast automatically to the type of the destination .
public void CopyTo(KeyValuePair[] array, int arrayIndex)
{
_dictionary.CopyTo(array, arrayIndex);
}
#endregion
#region IEnumerable<KeyValuePair> Members
///
/// Returns an enumerator that iterates through the collection.
///
///
/// A that can be used to iterate through the collection.
///
public IEnumerator<KeyValuePair> GetEnumerator()
{
return _dictionary.GetEnumerator();
}
#endregion
#region IEnumerable Members
[SuppressMessage(“Microsoft.Design”, “CA1033:InterfaceMethodsShouldBeCallableByChildTypes”)]
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#region Public Constructor
///
/// Initializes a new instance of the class.
///
/// The dictionary to wrap.
public ReadOnlyDictionary(IDictionary dictionary)
{
if((_dictionary = dictionary) == null) throw new ArgumentNullException(“dictionary”);
}
#endregion
}
Replace ExceptionHelper calls to just instanciate a new NotSupportedException
Good idea, if someone keeps calling (and failing) the methods in a loop. Thank you.
One Trackback/Pingback
[…] Can you think of any reason to do so? I can’t. It’s another “we’ll never know“. […]
Post a Comment