AutoDictionary for objects with a key property
The single most surprising thing that jumps at me is that an AutoDictionary doesn't implement IDictionary, and therefore can't be used as such. This is a rather major oversight, enough to be a showstopper in deciding whether or not I would use this data structure or not.

Short of implementing and exposing an Add(object, object) method, this AutoDictionary is simply not a dictionary as far as client code is concerned - it's a [keyed] collection, or an enumerable, but not a dictionary.

I would definitely try to find a way to implement the generic IDictionary&lt;TKey,TValue&gt; interface on top of IDictionary, too.

How? Well you already have a TKey generic type parameter, so a generic dictionary implementation would definitely be easy. The non-generic interface could validate the type of the key parameter (e.g. the first object in the Add(object, object) method) and throw some ArgumentException if the type can't be cast to TKey.

I'd also add a constructor that intakes the IDictionary dependency:

public AutoDictionary(IDictionary&lt;TKey, TItem&gt; source, Func&lt;TItem, TKey&gt; keySelector)
    : this(keySelector)
{
    _items = source;
}


Accepting a generic dictionary constrained with TKey would make the _items assignment compile and guaranteed to work, but would would still need to validate that the existing keys are those returned by the keySelector, and throw an exception otherwise.

Why is the second generic type parameter named TItem, when every IDictionary reference in the framework names it TValue? That's another rather surprising detail.



This is bad:


public void CopyTo(TItem[] array, int arrayIndex) { }



The method should at least throw a NotImplementedException. This no-op member is part of the interface, the contract you've signed when you decided to implement it: IMO leaving it unimplemented breaks the Liskov Substitution Principle, which means your implementation cannot be used in place of any other ICollection implementation. It should populate the array parameter with all values in stored in _items.



The class isn't sealed, which means a new class could be derived from it. Consider implementing the interface members as virtual, so their implementation could be overridden in inherited types - or outright seal the class.