How to make a generic class with inheritance?

2020-02-13 05:33发布

问题:

How can I make the following code work? I don't think I quite understand C# generics. Perhaps, someone can point me in the right direction.

    public abstract class A
    {
    }

    public class B : A
    {
    }

    public class C : A
    {
    }

    public static List<C> GetCList()
    {
        return new List<C>();
    }

    static void Main(string[] args)
    {
        List<A> listA = new List<A>();

        listA.Add(new B());
        listA.Add(new C());

        // Compiler cannot implicitly convert
        List<A> listB = new List<B>();

        // Compiler cannot implicitly convert
        List<A> listC = GetCList();

        // However, copying each element is fine
        // It has something to do with generics (I think)
        List<B> listD = new List<B>();
        foreach (B b in listD)
        {
            listB.Add(b);
        }
    }

It's probably a simple answer.

Update: First, this is not possible in C# 3.0, but will be possible in C# 4.0.

To get it running in C# 3.0, which is just a workaround until 4.0, use the following:

        // Compiler is happy
        List<A> listB = new List<B>().OfType<A>().ToList();

        // Compiler is happy
        List<A> listC = GetCList().OfType<A>().ToList();

回答1:

you could always do this

List<A> testme = new List<B>().OfType<A>().ToList();

As "Bojan Resnik" pointed out, you could also do...

List<A> testme = new List<B>().Cast<A>().ToList();

A difference to note is that Cast<T>() will fail if one or more of the types does not match. Where OfType<T>() will return an IEnumerable<T> containing only the objects that are convertible



回答2:

The reason this does not work is because it cannot be determined to be safe. Suppose you have

List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = giraffes; // suppose this were legal.
// animals is now a reference to a list of giraffes, 
// but the type system doesn't know that.
// You can put a turtle into a list of animals...
animals.Add(new Turtle());  

And hey, you just put a turtle into a list of giraffes, and the type system integrity has now been violated. That's why this is illegal.

The key here is that "animals" and "giraffes" refer to the SAME OBJECT, and that object is a list of giraffes. But a list of giraffes cannot do as much as a list of animals can do; in particular, it cannot contain a turtle.