【问题标题】:Cast custom collection to implemented interfaces将自定义集合转换为实现的接口
【发布时间】:2020-04-15 13:57:06
【问题描述】:

在下文中,为什么 Todos1 有效,而 Todos2 无效?如何让它发挥作用?

class Program
{
    static void Main(string[] args)
    {
        _todos = new CustomCollection<Todo>();
    }

    private static CustomCollection<Todo> _todos;

    public static IEnumerable<ITodo> Todos1
    {
        get { return _todos; }
    }

    public static ICustomCollection<ITodo> Todos2
    {
        get { return _todos; }
    }

    public class CustomCollection<T> : Collection<T>, ICustomCollection<T>
    {
    }

    public interface ICustomCollection<T> : IEnumerable<T>
    {
    }

    public interface ITodo
    {
    }

    public class Todo : ITodo
    {
        public string Description { get; set; }
    }
}

【问题讨论】:

    标签: c# generics ienumerable


    【解决方案1】:

    这就是方差的工作原理; IEnumerable&lt;T&gt;实际上是IEnumerable&lt;out T&gt;,意思是协变;这意味着任何IEnumerable&lt;Todo&gt; 也是IEnumerable&lt;ITodo&gt;,因为任何Todo 都是ITodo

    但是,集合/列表/等不是协变(或逆变)的;所以这里没有隐含的可转换性。原因是:

    • 你有一个CustomCollection&lt;Todo&gt;
    • 如果可以转换为CustomCollection&lt;ITodo&gt;,你可以Add 任何 ITodo
    • 包括class SomethingElse : ITodo,它不是 Todo
    • 所以你的Todos 集合中会有一个非Todo

    编译器在保护你!

    【讨论】:

    • 所以,必须是interface ICustomCollection&lt;out T&gt; : IEnumerable&lt;T&gt;才能工作;对吗?
    【解决方案2】:

    您应该将您的ICustomCollection&lt;T&gt; 接口声明为covariant

    public interface ICustomCollection<out T> : IEnumerable<T>
    {
    }
    

    否则它是不变的,您只能将其转换为用于声明的相同 Todo 类型,而不是 ITodo 接口。

    IEnumerable&lt;T&gt; 已经具有协变泛型类型参数T,因此第一个属性按预期工作。

    【讨论】:

      猜你喜欢
      • 2012-09-27
      • 2019-07-26
      • 2011-06-05
      • 2018-07-17
      • 1970-01-01
      • 1970-01-01
      • 2017-01-11
      • 2011-08-31
      • 2011-02-22
      相关资源
      最近更新 更多