Cast List <object>和Cast IEnumerable <object>之间的区别是什么?

时间:2016-02-03 12:45:19

标签: c# class generics interface casting

我尝试将对象(对象包含List<Apple>)转换为List<object>,但失败并出现异常:

  

无法将类型为'System.Collections.Generic.List [list_cast_object_test.Apple]'的对象强制转换为'System.Collections.Generic.List [System.Object]'。

当我用ListIEnumerable(一个界面)替换IList时,它运作良好,我不明白其中的区别......

代码如下:

    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; }
}

有人可以解释一下它发生了什么?强制转换为通用接口和转换为泛型类有什么区别?

2 个答案:

答案 0 :(得分:6)

这是因为在@RunWith(SpringJUnit4ClassRunner::class) @ContextConfiguration(classes = arrayOf(ApplicationAssembly::class), loader = SpringApplicationContextLoader::class) @WebIntegrationTest open class CandidateProfileControllerTest { @Inject lateinit var profileRepo: CandidateProfileRepository //etc a few more deps used to setup test data @Test open fun getById() { val greg = CandidateProfile("123", "12312", "Greg", "Jones", dateOfBirth = Date(), gender = Gender.MALE, biography = "ABC", maxMatchableAge = null, maxMatchableDistance = null) profileRepo.save(greg) val auth = given().header("content-type", "application/json") .body(testCredentials) .post("/authorization/social").peek().asString() val accessToken: String = from(auth).get("accessToken") given().header("Access-Token", accessToken). header("API-Key", testAPIKey()). get("/profile/${greg.id}"). peek().then(). body("stageName", notNullValue()) } IEnumerable<T>中,T List<T>中的协变性不支持协方差。

详细了解Covariance and Contraviance in c#

如果你想做那样的事情,那么你必须使用T重载,它会将它包装成对象类型,如:

ToList<T>()

此处我们可以将 List<object> result = resultObject.ToList<object>(); 转换为List<Apple>,原因是新List<Object>创建List<T>类型为T,但我们无法转换原始Object {1}}引用List<Apple>

在这种情况下,它将创建List<object>类型的实例,并将对您的类型的引用存储为Object类型的引用,但在值类型或strcuts的情况下,它将具有装箱成本。

答案 1 :(得分:4)

IEnumerable<T>是一个接口,由于类型T被定义为协变(实际上是IEnumerable<out T>,请注意out),您可以强制转换{{1} }}到基础实现,因此T是类型IEnumerable<object列表中的有效广播。

但是,类型List<Apple>不等于List<Apple>类型,列表List<object>也不是List<Apple>List<object>上的类型参数是协变,因此该广告无效。