C# 将自定义集合强制转换为实现的接口

C# 将自定义集合强制转换为实现的接口,c#,generics,ienumerable,C#,Generics,Ienumerable,在下面的例子中,为什么Todos1有效,而Todos2无效?如何让它工作 class Program { static void Main(string[] args) { _todos = new CustomCollection<Todo>(); } private static CustomCollection<Todo> _todos; public static IEnumerable<ITodo

在下面的例子中,为什么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实际上是IEnumerable,意思是它是协变的;这意味着任何IEnumerable的东西都是IEnumerable的,因为任何Todo都是ITodo

然而,集合/列表/etc不是协变或逆变的;所以这里没有隐含的可铸造性。原因是:

你有自己的收藏 如果这是可铸造到CustomCollection,您可以添加任何ITodo 包括课堂上的一些事情:ITodo这不是一个待办事项 所以在你的待办事项集合中有一个非待办事项
编译器正在保护你

这就是方差的工作原理;IEnumerable实际上是IEnumerable,意思是它是协变的;这意味着任何IEnumerable的东西都是IEnumerable的,因为任何Todo都是ITodo

然而,集合/列表/etc不是协变或逆变的;所以这里没有隐含的可铸造性。原因是:

你有自己的收藏 如果这是可铸造到CustomCollection,您可以添加任何ITodo 包括课堂上的一些事情:ITodo这不是一个待办事项 所以在你的待办事项集合中有一个非待办事项 编译器正在保护你

您应该将ICustomCollection接口声明为

公共接口ICustomCollection:IEnumerable { } 否则它是不变的,您只能将其强制转换为用于声明的相同Todo类型,而不是ITodo接口

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

您应该将ICustomCollection接口声明为

公共接口ICustomCollection:IEnumerable { } 否则它是不变的,您只能将其强制转换为用于声明的相同Todo类型,而不是ITodo接口

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

因此,它必须是接口ICustomCollection:IEnumerable才能工作;对吗?所以,它必须是接口ICustomCollection:IEnumerable才能工作;正当