Re: Casting generic collections & inheritance

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance



Random aside: the logic I can see here makes perfect sence for anything that
allows addition etc - however, some casts could be sensible defined. In
particular (and most usefully) couldn't a List<X> quite safely implement
IEnumerable<T> for each T in X's inheritance tree?

Unless I am missing something this fails at the moment, but would be very
useful (to me, at least).

Example (which doesn't work) below.

Any thoughts? Am I missing an obvious "this wouldn't work because..."?

public class A {
public readonly string Name; // [sic] for brevity / demo
public A(string name) { name = Name; }
}
public class B : A {
public readonly int ID;
public B(string name, int id) : base(name) { id = ID; }
}
public class Program {

public static void Main() {
List<B> list = new List<B>();
list.Add(new B("Fred", 1));
list.Add(new B("Barney", 2));
list.Add(new B("Wilma", 3));
list.Add(new B("Betty", 4));
// *** following fails (as per spec) at runtime
// (would be nice if a: worked, and b: didn't need cast)
IEnumerable<A> items = (IEnumerable<A>) list;
foreach(A item in items) {
Console.WriteLine(item.Name);
}
Console.ReadLine();

}
}

"Jon Skeet [C# MVP]" <skeet@xxxxxxxxx> wrote in message
news:1137081986.209287.87140@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
> Michael Bray wrote:
>> > No it's not. If you could treat a Queue<string> as a Queue<object>
>> > then you could add a new object() to it - and suddenly anything
>> > viewing it
>> > as a Queue<string> would be in trouble.
>>
>> Jon, this is backwards to what Adam is saying... Its not that we want
>> to insert objects into the List<string> but we (well, me at least) would
>> like to be able to, for example, pass a List<string> to a function that
>> takes a List<object>.
>
> That's *exactly* what I said - if you could pass a List<string> to
> something expecting List<object> that's treating a List<string> as a
> List<object>, isn't it?
>
> The method you would pass the list to could do:
>
> theList.Add (new object());
>
> What would you expect to happen at that point? The caller is still
> expecting every element to be a string, so either you allow it and they
> blow up when they use the element as a string, or you blow up at the
> call to Add (which is what array covariance effectively does).
>
>> So for example, something like this is not possible, but it sure would
>> be nice:
>
> <snip>
>
>> Although after writing this example, I can see where the problem is...
>> the ShowNames function in this case doesn't modify the list, but that's
>> only because of the nature of the function. Some other function that
>> took a List<Person> might want to modify it and add a Person object
>> which would violate the definition of the List<Farmer>. So I guess it
>> makes sense after all! :)
>
> Exactly. That's what I was trying to say. Just out of interest, how
> could I have expressed it more clearly? It's a fairly common question -
> I'd like to know how to address it better. Would including source code
> have helped.
>
>> For anyone else following this thread, though, here's two nice ways to
>> convert (for Lists, at least from one type to another). Although I will
>> add that in light of the above, this should only be used for temporary
>> conversion in the case that you want to pass a List<DerivedClass> to a
>> function that processes a List<BaseClass> in a read-only fashion.
>>
>> otherPeople = new List<Person>(farmers.ToArray());
>>
>> otherPeople = farmers.ConvertAll(new Converter<Farmer, Person>(
>> delegate(Farmer f) { return (Person)f; }
>> ));
>
> I haven't tried, but I'm sure there's an easy way of writing a generic
> converter that can always do an identity conversion (i.e. convert from
> S to T where S : T).
>
>> The second one actually is more generic and doesn't even require that
>> the two classes be a base/derived class pair. In the example given,
>> however, this is the case, which is why the anonymous method code is
>> just a simple cast from Farmer to Person.
>
> In fact, the cast isn't even needed, is it?
>
> Jon
>


.



Relevant Pages

  • Re: Casting generic collections & inheritance
    ... also - obviously it would have to use explicit implementation (rather than ... > public class B: A { ... >>> convert (for Lists, at least from one type to another). ... >>> just a simple cast from Farmer to Person. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Generic ICloneable
    ... ICloneablethen the object should be an X and you can cast directly to ... public X Clone() {... ... If you had a generic IClonable interface, ... public class MyClass: IClonable ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Object casting (newbie)
    ... > what happens if I cast my child object to the parent objects? ... > If I cast a long to a byte I lose data. ... > public class child1 extendes cParent{ ... > public int getValue() { ...
    (comp.lang.java.programmer)
  • Re: Inheritance Problem
    ... class without having to cast it every time. ... public class PokerTable: CardTable ... public PokerPlayer[] pokerplayers ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Casting generic collections & inheritance
    ... public class B: A { ... >>> convert (for Lists, at least from one type to another). ... >> converter that can always do an identity conversion (i.e. convert from ... >>> just a simple cast from Farmer to Person. ...
    (microsoft.public.dotnet.languages.csharp)