Michi Henning wrote:
On Aug 28, 4:30 pm, Jon Skeet [C# MVP] <sk...@pobox.comwrote:
>Suppose your ICollection<ICollection<int>was actually a
List<List<int>at runtime. Using the interface version, someone could
add a LinkedList<intto it, at which point the type safety has been
broken.
I'm sorry, I don't follow that. All the formal parameter types says is
that we have ICollection<intof ICollection<int>.
(Well, actually it says you have an ICollection<of ICollection<int>,
or in other words an ICollection<ICollection<int>>. I think you knew
that, but just to be clear...)
Anyway, that's correct. That is _all_ it says.
Let's assume you're allowed to do what you want. That means that from
the point of view of the code within that method, it could put anything
into the ICollection<ICollection<int>as long as it's an
ICollection<int>. Any number of generic classes meet this requirement.
Jon's example was the LinkedList<intgeneric class. So, let's assume
that you pass a List<List<int>to the method. Then let's assume that
the method tries to add a LinkedList<intto the
ICollection<ICollection<int>in the method. This would be legal under
your suggested rules. Unfortunately, this would also allow your
List<List<int>(which is what was actually passed to the method and
which is the class being modified when you add the LinkedList<int>) to
contain a LinkedList<int>.
That violates the requirement that the List<List<int>only contain
instances of List<int>.
So, if someone add a few List<intand another few LinkedList<intto
the collections, what's broken?
If the original collection is a List<List<int>>, that's a serious
problem, to have a LinkedList<intas an element of the collection.
Both are ICollection<int>, so
everything would work fine, as far as I can see.
As far as the method knows, the items in the collection are only
ICollection<intinstances. The problem is that the collection is
really something else, and putting arbitrary ICollection<intinstances
into it can break the actual type of the collection.
I just don't get it: I can pass a List<intas an ICollection<int>.
Yes, that's true, you can. List<intimplements ICollection<intand so
it can be used anywhere that an ICollection<intis required.
But you can't pass a List<intas a List<objector an
ICollection<object>. And it is for the same reason. The issue here
isn't about whether the contained element is compatible with the
declared contained element in the method. It's whether the outer
collection itself is identical.
The receiver of the list knows that it is an ICollection<int>, so the
receiver cannot do anything but invoke ICollection operations on the
passed parameter (ignoring introspection and down-casts).
But the analog here isn't passing a List<intas an ICollection<int>.
The true analog would be passing a List<intas an ICollection<object>.
And that's not allowed.
Now, if I have an ICollection<ICollection<int>>, why shouldn't the
same apply. The receiver gets a collection of collections. Some of the
elements of the outer collection might be List<int>, other elements
might LinkedList<int>, but so what?
The problem isn't whether the method being called can safely use the
list. The problem is whether the list can be guaranteed to remain
correct relative to its actual type. That is, when the method is done,
can the caller expect the list to still only have List<intelements?
Because the method doesn't know anything about the type except the type
of the parameter, the answer to that question is no. The method could
have added anything that implements ICollection<intto the list,
including something other than a List<int(like the LinkedList<int>
that Jon mentioned).
The receiver still can only invoke
operations on ICollection<inton the elements of the outer list.
That's true. But it doesn't have anything to do with why you can't pass
the List<List<int>>
I honestly can't see why this would break type safety in any way.
I hope the above explains it satisfactorily.
Pete