简体   繁体   中英

How to cast List<ClassB> to List<ClassA> when ClassB inherits from ClassA?

I deserialized json string to List<ClassB> and now I want to cast it to List<ClassA> before I return it from BindModel method. I need casting because the methods expects to get List<ClassA> .

Why I get error while casting? After all, ClassB inherits from ClassA . What should I do?

PS this question is extended from this post . In line new DataContractJsonSerializer(typeof(List<ClassB>)); instead of List<ClassB> the type will be constructed at runtime.

    public override object BindModel(...)
    {
          var serializer = new DataContractJsonSerializer(typeof(List<ClassB>));
          MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("[{\"id\":\"1\",\"name\":\"name\"}]"));
          var list = serializer.ReadObject(ms);

          return (List<ClassA>)list;
    }

    [KnownType(typeof(ClassA))]
    [DataContract]
    public class ClassA
    {
        public ClassA();
    }

    [KnownType(typeof(ClassB))]       
    [DataContract]
    public class ClassB : ClassA
    {
        [DataMember(Name = "id")]
        public int Id { get; set; }
        [DataMember(Name = "name")]
        public string CategoryName { get; set; }
    }

You can use

 Cast<T>()

For example:

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

This in fact is inferior to Linq and is implemented on IEnumerable rather than IEnumerable<T> but still is useful. It is not efficient since as I said, it tries to cast it.

Remember List does not allow for covariance which is a nuisance. It is preferable to use IEnumerable<T> as interface rather than List.

You can say:

 IEnumerable<B> listOfB = new List<B>();
 IEnumerable<A> listOfA = listOfB; // no casting required

You can use the Cast Method .

return list.Cast<ClassB>();

Have a look at this question about Co and Contra Variance

I would cast the lists like this:

var listB = GetListOfB();  // returns List<B>
var listA = listB.Select(q => (A)q).ToList();

Will that work for you?

You can't cast a List of SubType to a List of SuperType . Suppose I have a list of Tortoises, and I was able to cast it to a list of Animals. Then I could add a lion, to a list of Tortoises, but a Lion isn't of the correct type.

With enumerables, you can do this, however. The previous posters are quite correct in saying that you can cast a List of SubType to an IEnumerable of SuperType . In fact, in C# 4, and IEnumerable SubType is an IEnumerable of SuperType . This is because the generic parameter is specified as an out parameter.

To create a List<BaseClass> from a List<DerivedClass> , a cast will not suffice, as other answers have noted. You need to construct a new list.

I'm not particularly happy with the code that other answers have suggested, though, so I'm offering my own solution. I would do it this way:

var baseClassList = new List<BaseClass>(derivedClassList.Cast<BaseClass>());

Some might prefer this:

var baseClassList = derivedClassList.Cast<BaseClass>().ToList();

I prefer the first one because it makes it easy to change the type from List<T> to any other collection with a constructor that takes an IEnumerable<T> .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM