将自定义集合转换为已实现的接口

Cast custom collection to implemented interfaces

下面,为什么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; }
    }
}

方差就是这样运作的; IEnumerable<T>实际上是IEnumerable<out T>,意思是协变;这意味着任何 IEnumerable<Todo> 也是 IEnumerable<ITodo>,因为任何 Todo 都是 ITodo.

然而,collections / lists / etc not协变(或逆变);所以这里没有隐含的可铸性。原因是:

  • 你有一个CustomCollection<Todo>
  • 如果可以转换为 CustomCollection<ITodo>,你可以 Add any ITodo
  • 包括 class SomethingElse : ITodo,这是 不是 Todo
  • 所以你的 collection 中有一个非 Todo Todo

编译器在保护你!

您应该将 ICustomCollection<T> 接口声明为 covariant

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

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

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