我尝试将对象(对象包含List<Apple>
)转换为List<object>
,但失败并出现异常:
无法将类型为'System.Collections.Generic.List [list_cast_object_test.Apple]'的对象强制转换为'System.Collections.Generic.List [System.Object]'。
当我用List
或IEnumerable
(一个界面)替换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; }
}
有人可以解释一下它发生了什么?强制转换为通用接口和转换为泛型类有什么区别?
答案 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>
上的类型参数是不协变,因此该广告无效。