通用接口中的协方差

L.T*_*hin 5 .net c# generics variance

我想创建一个可排序的observableCollection,所以我开始创建一个继承observable的类,用一些方法对它进行排序,然后我希望该类将索引保存到子节点中,所以我创建了一个接口,公开了一个索引属性,其中我可以写入,并且我将我的集合类的T表示为我的接口,然后我希望能够从avery项目访问parentCollection,这里问题已经开始,因为父集合的类型是通用的...我已经尝试了很多解决方案,我认为协方差或不变性是方法,但我不能让它工作......

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClassLibrary1
{
    public class SortableCollection<T> : System.Collections.ObjectModel.ObservableCollection<T>, ISortableCollection<T> where T : ISortable<T>
    {
        public void Sort()
        {
            //We all know how to sort something
            throw new NotImplementedException();
        }

        protected override void InsertItem(int index, T item)
        {
            item.Index = index;
            item.ParentCollection = this;
            base.InsertItem(index, item);
        }
    }

    public interface ISortableCollection<T> : IList<T>
    {
        void Sort();
    }

    public interface ISortable<T>
    {
        Int32 Index { get; set; }
        ISortableCollection<T> ParentCollection { get; set; }
    }

    public class BaseClass : ISortable<BaseClass>
    {
        public int Index { get; set; }

        public ISortableCollection<BaseClass> ParentCollection { get; set; }
    }

    public class DerivedClass : BaseClass { }

    public class Controller
    {
        SortableCollection<BaseClass> MyBaseSortableList = new SortableCollection<BaseClass>();
        SortableCollection<DerivedClass> MyDerivedSortableList = new SortableCollection<DerivedClass>();

        public Controller()
        {
            //do things
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这或多或少是设置.我希望能够创建一个SortableCollection<DerivedClass>但类型不匹配...这是正确的方法吗?

确切的错误是

错误1类型'ClassLibrary1.DerivedClass'不能用作泛型类型或方法中的类型参数'T' 'ClassLibrary1.SortableCollection<T>'.没有从"ClassLibrary1.DerivedClass"到的隐式引用转换'ClassLibrary1.ISortable<ClassLibrary1.DerivedClass>'.c:\ users\luigi.trabacchin\documents\visual studio 2013\Projects\ClassLibrary1\ClassLibrary1\Class1.cs 48 89 ClassLibrary1

Eri*_*ert 8

问题是你的约束T是" T必须是一个I<T>",你已经传递了一个DerivedClassfor T,但是DerivedClass不能转换为I<DerivedClass>,它可以转换为I<BaseClass>.

我不知道你想用约束来表示什么T是一个I<T>.我知道人们经常使用这种模式来试图表示C#类型系统实际上没有实现的约束.有关详细信息,请参阅有关该主题的文章

http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx

我鼓励你大大简化一些事情; 你似乎试图在类型系统中捕获太多.

之所以I<D>不能转换I<B>是因为为了使方差起作用,必须将接口标记为支持方差; 标志的T使用outin依赖于你是否想要协方差或逆变.

但是,由于IList<T>是不变的,因此使派生接口协变或逆变是不合法的.请考虑一下IEnumerable<T>,因为它是协变的T.

为了使接口具有协变性,T它只需要T输出位置使用.List<T>采用T在输入和输出的位置,因此它不能是协变或逆变.