Why doesn't generic ICollection implement IReadOnlyCollection in .NET 4.5?
There are probably several reasons. Here are some:
Huge backwards compatibility problems
How would you write the definition of
ICollection<T>
? This looks natural:interface ICollection<T> : IReadOnlyCollection<T> { int Count { get; } }
But it has a problem, because
IReadOnlyCollection<T>
also declares aCount
property (the compiler will issue a warning here). Apart from the warning, leaving it as-is (which is equivalent to writingnew int Count
) allows implementors to have different implementations for the twoCount
properties by implementing at least one explicitly. This might be "amusing" if the two implementations decided to return different values. Allowing people to shoot themselves in the foot is rather not C#'s style.OK, so what about:
interface ICollection<T> : IReadOnlyCollection<T> { // Count is "inherited" from IReadOnlyCollection<T> }
Well, this breaks all existing code that decided to implement
Count
explicitly:class UnluckyClass : ICollection<Foo> { int ICollection<Foo>.Count { ... } // compiler error! }
Therefore it seems to me that there's no good solution to this problem: either you break existing code, or you force an error-prone implementation on everyone. So the only winning move is not to play.
Jon was right here https://stackoverflow.com/a/12622784/395144 , you should mark his reply as the answer:
int ICollection<Foo>.Count { ... } // compiler error!
Since interfaces can have explicit implementations, extracting base interfaces is not backward compatible (with base classes you don't have this problem).
That's why...
Collection<T> : IReadOnlyCollection<T>
List<T> : IReadOnlyList<T>
Dictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>
... but not their interfaces.
IMHO, they did a design error initially, quite unresolvable now (without breaking things).
EDIT: hiding doesn't help, old (explicit) implementations won't still build (without modifying the code):
interface INew<out T> { T Get(); }
interface IOld<T> : INew<T>
{
void Set(T value);
new T Get();
}
class Old<T> : IOld<T>
{
T IOld<T>.Get() { return default(T); }
void IOld<T>.Set(T value) { }
}
'Sample.Old' does not implement interface member 'Sample.INew.Get()'
It would be semantically wrong, because obviously, not every ICollection
is read-only.
That said, they could have called the interface IReadableCollection
, while an implementation could be called ReadOnlyCollection
.
However, they didn't go that route. Why? I saw a BCL team member write that they didn't want the collections API to become too convoluted. (Although it already is, frankly.)