【问题标题】:Cast fails from ICollection<TestCastChild> to ICollection<ICastBase> [duplicate]从 ICollection<TestCastChild> 到 ICollection<ICastBase> 的转换失败 [重复]
【发布时间】:2015-06-29 18:14:28
【问题描述】:

我正在使用反射来获取ICollection&lt;TestCastChild&gt; 的属性并将其转换为ICollection&lt;ICastBase&gt;。 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; }
}

然后进行测试:

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

【问题讨论】:

  • 是的,这是重复的。在这里看到答案后,我能够搜索“协变”并找到其他答案。

标签: c#


【解决方案1】:

不能ICollection&lt;Derived&gt; 转换为ICollection&lt;Base&gt;,因为ICollection&lt;T&gt; 不是协变

如果可能,您可以将ICollection&lt;Dog&gt; 转换为ICollection&lt;Mammal&gt;,然后将Cat 添加到集合中,因为它也是Mammal

可以做什么,是从IReadOnlyCollection&lt;Derived&gt; 转换为IReadOnlyCollection&lt;Base&gt;,因为IReadOnlyCollection&lt;out T&gt;协变的。如果您的具体集合类型实现了IReadOnlyCollection&lt;out T&gt;(并且List&lt;T&gt; 实现了),它将工作得很好,但您只会获得底层集合的只读接口。这样,仍然保留了类型安全性。

请注意,您也可以使用IReadOnlyList&lt;out T&gt;,它继承自IReadOnlyCollection&lt;out T&gt;,并添加了一个索引器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多