Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between Cast List<object> and Cast IEnumerable<object>

I tried to make a conversion from object (the object contains a List<Apple>) to List<object>, and it fails with an exception:

Unable to cast object of type 'System.Collections.Generic.List[list_cast_object_test.Apple]' to type 'System.Collections.Generic.List[System.Object]'.

When I have replaced List with IEnumerable or IList (an interface) it works well, and I don't understand the difference....

The code looks like:

    private void Form1_Load(object sender, EventArgs e) {
        object resultObject = GetListAsObject();

        // this cast works fine, it's normal...
        var resAsIt = (List<Apple>)resultObject;

        // also when I use a generic interface of 'object' cast works fine
        var resAsIEnumerable = (IEnumerable<object>)resultObject;

        // but when I use a generic class of 'object' it throws me error: InvalidCastException
        var resAsList = (List<object>)resultObject;
    }

    private object GetListAsObject() {
        List<Apple> mere = new List<Apple>();
        mere.Add(new Apple { Denumire = "ionatan", Culoare = "rosu" });
        mere.Add(new Apple { Denumire = "idared", Culoare = "verde" });
        return (object)mere;
    }
}
public class Apple {
    public string Denumire { get; set; }
    public string Culoare { get; set; }
}

Someone may explain me what it happens? What is the difference between cast to a generic interface and cast to a generic class?

like image 348
Ovidiu Rudi Avatar asked Dec 24 '22 09:12

Ovidiu Rudi


2 Answers

It is because in IEnumerable<T> T is covariant while in List<T> T does not support Covariance.

See more about Covariance and Contraviance in c#

If you want to do thing like that you then have to use ToList<T>() overload which will wrap it to object type like:

 List<object> result = resultObject.ToList<object>();

Here we are able to convert List<Apple> to List<Object> due to new List<T> creation where T is of type Object but we cannot cast the original List<Apple> reference to List<object>.

In this case it will create instance of Object type and will store reference to your type as reference of type object , but in case of Value Types or strcuts it will have boxing cost.

like image 81
Ehsan Sajjad Avatar answered Dec 28 '22 05:12

Ehsan Sajjad


IEnumerable<T> is an interface, and since the type T is defined covariant (it is actually IEnumerable<out T>, note the out), you can cast the T to a base implementation, so IEnumerable<object is a valid cast on your list of type List<Apple>.

However, the type List<Apple> is not equal to the type List<object>, nor does the list List<Apple> derived from List<object>. The type parameter on List<T> is not covariant, hence that cast is invalid.

like image 43
Patrick Hofman Avatar answered Dec 28 '22 05:12

Patrick Hofman