C# ICollection的强制转换失败<;TestCastChild>;到ICollection<;ICastBase>;

C# ICollection的强制转换失败<;TestCastChild>;到ICollection<;ICastBase>;,c#,C#,我使用反射来获取一个属性,该属性是ICollection,并将其转换为ICollection。TestCastChild实现的ICastBase。当我尝试转换集合时,转换失败。我肯定我错过了一些简单的东西。我不明白这为什么会失败 public interface ICastBase { int Id { get; set; } } public interface ICastChild : ICastBase { string Name { get; set; } } pub

我使用反射来获取一个属性,该属性是
ICollection
,并将其转换为
ICollection
。TestCastChild实现的ICastBase。当我尝试转换集合时,转换失败。我肯定我错过了一些简单的东西。我不明白这为什么会失败

public interface ICastBase
{
    int Id { get; set; }
}

public interface ICastChild : ICastBase
{
    string Name { get; set; }
}

public abstract class TestCastBase : ICastBase
{
    public int Id { get; set; }
}

public class TestCastChild : TestCastBase, ICastChild
{
    public string Name { get; set; }
}

public class TestCastParent : TestCastBase
{
    public virtual ICollection<TestCastChild> Children { get; set; }
}
公共接口ICastBase
{
int Id{get;set;}
}
公共接口ICastChild:ICastBase
{
字符串名称{get;set;}
}
公共抽象类TestCastBase:ICastBase
{
公共int Id{get;set;}
}
公共类TestCastChild:TestCastBase,ICastChild
{
公共字符串名称{get;set;}
}
公共类TestCastParent:TestCastBase
{
公共虚拟ICollection子项{get;set;}
}
然后进行测试:

[TestMethod]
public void TestCast()
{
    var parent = new TestCastParent();
    parent.Children = parent.Children ?? new List<TestCastChild>();
    parent.Children.Add(new TestCastChild{Name = "a"});
    parent.Children.Add(new TestCastChild { Name = "b"});
    parent.Children.Add(new TestCastChild { Name = "c"});

    var propInfos = parent.GetType().GetProperties();
    foreach (var propertyInfo in propInfos)
    {
        if (propertyInfo.PropertyType.GetMethod("Add") != null)
        {
            var tmpVal = propertyInfo.GetValue(parent);
            //This evaluates to null
            var cast1 = tmpVal as ICollection<ICastBase>; 
            //This evaluates to null
            var cast2 = tmpVal as ICollection<ICastChild>;
            //This evaluates to the expected value
            var cast3 = tmpVal as ICollection<TestCastChild>;
        }               
    }
}
[TestMethod]
公共void TestCast()
{
var parent=新的TestCastParent();
parent.Children=parent.Children??新列表();
Add(newtestcastchild{Name=“a”});
Add(newtestcastchild{Name=“b”});
Add(newtestcastchild{Name=“c”});
var propinfo=parent.GetType().GetProperties();
foreach(PropInfo中的var propertyInfo)
{
if(propertyInfo.PropertyType.GetMethod(“添加”)!=null)
{
var tmpVal=propertyInfo.GetValue(父级);
//其计算结果为null
var cast1=tmpVal作为ICollection;
//其计算结果为null
var cast2=tmpVal作为ICollection;
//这将计算为预期值
var cast3=tmpVal作为ICollection;
}               
}
}

由于
ICollection
不是协变的,因此您不能从
ICollection
强制转换为
ICollection

如果可能,您可以将
i集合
投射到
i集合
,然后将
Cat
添加到集合中,因为它也是
哺乳动物

您可以执行的操作是从
IReadOnlyCollection
强制转换为
IReadOnlyCollection
,因为
IReadOnlyCollection
是协变的。如果您的具体集合类型实现了
IReadOnlyCollection
(并且
List
实现了),那么它可以正常工作,但您只能获得一个到基础集合的只读接口。这样,类型安全性仍然保持不变


请注意,您还可以使用
IReadOnlyList
,它继承自
IReadOnlyCollection
,并添加索引器。

无法将
ICollection
转换为
ICollection
,因为
ICollection
不是协变的

如果可能,您可以将
i集合
投射到
i集合
,然后将
Cat
添加到集合中,因为它也是
哺乳动物

您可以执行的操作是从
IReadOnlyCollection
强制转换为
IReadOnlyCollection
,因为
IReadOnlyCollection
是协变的。如果您的具体集合类型实现了
IReadOnlyCollection
(并且
List
实现了),那么它可以正常工作,但您只能获得一个到基础集合的只读接口。这样,类型安全性仍然保持不变


请注意,您还可以使用
IReadOnlyList
,它继承自
IReadOnlyCollection
,并添加索引器。

是的,这是一个重复项。在这里看到答案后,我可以搜索“协变”并找到其他答案。是的,这是一个副本。在这里看到答案后,我能够搜索“协变”并找到其他答案。