C# 通用接口中的协方差

C# 通用接口中的协方差,c#,.net,generics,variance,C#,.net,Generics,Variance,我想创建一个可排序的observableCollection 所以我开始创建一个继承observable的类,并使用一些方法对其进行排序,然后我希望该类将索引持久化到child中,因此我创建了一个接口,该接口公开了一个可以写入的索引属性,我对集合类的T进行了成本培训,使其成为我的接口的一部分,然后我希望能够从avery项访问parentCollection,这里问题开始了,因为父集合的类型是泛型的。。。 我尝试过很多解决方案,我认为协方差或不变性是解决方法,但我无法让它工作 using Syst

我想创建一个可排序的observableCollection 所以我开始创建一个继承observable的类,并使用一些方法对其进行排序,然后我希望该类将索引持久化到child中,因此我创建了一个接口,该接口公开了一个可以写入的索引属性,我对集合类的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
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
命名空间类库1
{
公共类SortableCollection:System.Collections.ObjectModel.ObservableCollection,ISortableCollection其中T:ISortable
{
公共无效排序()
{
//我们都知道如何分类
抛出新的NotImplementedException();
}
受保护的覆盖无效插入项(int索引,T项)
{
项目索引=索引;
item.ParentCollection=此;
基本插入项(索引,项目);
}
}
公共接口ISortableCollection:IList
{
无效排序();
}
公共接口可移植
{
Int32索引{get;set;}
ISortableCollection父集合{get;set;}
}
公共类基类:ISortable
{
公共int索引{get;set;}
公共ISortableCollection父集合{get;set;}
}
公共类DerivedClass:基类{}
公共类控制器
{
SortableCollection MyBaseSortableList=新建SortableCollection();
SortableCollection MyDerivedSortableList=新建SortableCollection();
公共控制员()
{
//做事
}
}
}
这或多或少是一种设置。 我希望能够创建一个
SortableCollection
,但是类型不匹配。。。做这件事的正确方法是什么

准确的误差是

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


您需要
DerivedClass
成为一个
ISortable


问题是您对
T
的约束是“
T
必须是
I
”,并且您已经为
T
传递了
DerivedClass
,但是
DerivedClass
不能转换为
I
,它可以转换为
I

我不知道你试图用
t
成为
I
的约束来表示什么。我知道人们经常使用这种模式来表示C#type系统实际上没有实现的约束。有关详细信息,请参阅我的文章:

我鼓励你把事情大大简化;您似乎试图在类型系统中捕获太多内容

I
不能转换为
I
的原因是为了使差异生效,接口必须标记为支持差异;将
T
标记为
out
in
,具体取决于您想要的是协方差还是反方差

但是,由于IList是不变的,因此使派生接口协变或逆变是不合法的。考虑<代码> iQueDebug <代码>,因为它在代码< t>代码>中是协变的。


为了使接口在
T
中是协变的,它只需要在输出位置使用
T
<代码>列表
在输入和输出位置都使用
T
,因此它不能是协变或逆变的。

为了感谢大家,我将发布我最终得到的设计

using System;
using System.Collections;
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 where T : ISortable, IComparable, IComparable<T>
    {
        public new void Add(T item)
        {
            if (this.Items.Contains(item))
                throw new InvalidOperationException("This list can contain the same item only once");
            base.Add(item);
        }

        public void Sort()
        {
            var sorted = this.Items.ToList();
            sorted.Sort();
            for (var i = 0; i < this.Items.Count; i++)
            {
                if (object.ReferenceEquals(this.Items[i], sorted[i]))
                {
                    this.Items[i].Index = i;
                    continue;
                }
                // if u want to support duplicates create a nextIndexOf and start searching from i
                var previousIndex = IndexOf(sorted[i]);
                Move(previousIndex, i);
            }
        }

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

        protected override void RemoveItem(int index)
        {
            this.Items[index].ParentCollection = null;
            base.RemoveItem(index);
        }

        protected override void ClearItems()
        {
            foreach (var item in this.Items)
                item.ParentCollection = null;
            base.ClearItems();
        }

        protected override void SetItem(int index, T item)
        {
            this.Items[index].ParentCollection = null;
            item.Index = index;
            item.ParentCollection = this;
            base.SetItem(index, item);
        }

        protected override void MoveItem(int oldIndex, int newIndex)
        {
            this.Items[oldIndex].Index = newIndex;
            this.Items[newIndex].Index = oldIndex;
            base.MoveItem(oldIndex, newIndex);
        }
    }

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

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

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

        public ISortableCollection ParentCollection { get; set; }

        public int CompareTo(object obj)
        {
            return CompareTo(obj as BaseClass);
        }

        public int CompareTo(BaseClass other)
        {
            if (other == null)
                return 1;
            return this.Index.CompareTo(other.Index);
        }
    }

    public class DerivedClass : BaseClass { }

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

        public Controller()
        {
            //do things
            MyDerivedSortableList.Add(new DerivedClass());
            MyDerivedSortableList.Add(new DerivedClass());
            var derivedThing = new DerivedClass();
            MyDerivedSortableList.Add(derivedThing);
            var sibiling = derivedThing.ParentCollection[derivedThing.Index - 1] as BaseClass;  //way easier
            // switch the two objects order and call sort
            // calling a sort before the operation if indexes have been messed with
            // add an event to ISortable to notify the list the index has been changed and mark the list dirty
            derivedThing.Index -= 1;
            sibiling.Index += 1;
            derivedThing.ParentCollection.Sort();   // maybe the list was created where i couldn't access it
        }
    }
}
使用系统;
使用系统集合;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
命名空间类库1
{
公共类SortableCollection:System.Collections.ObjectModel.ObservableCollection,ISortableCollection其中T:ISortable,IComparable,IComparable
{
新增公共作废(T项)
{
如果(本项目包含(项目))
抛出新的InvalidOperationException(“此列表只能包含同一项一次”);
基础。添加(项目);
}
公共无效排序()
{
var sorted=this.Items.ToList();
sorted.Sort();
对于(var i=0;i((dynamic))item).ParentCollection = this;
using System;
using System.Collections;
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 where T : ISortable, IComparable, IComparable<T>
    {
        public new void Add(T item)
        {
            if (this.Items.Contains(item))
                throw new InvalidOperationException("This list can contain the same item only once");
            base.Add(item);
        }

        public void Sort()
        {
            var sorted = this.Items.ToList();
            sorted.Sort();
            for (var i = 0; i < this.Items.Count; i++)
            {
                if (object.ReferenceEquals(this.Items[i], sorted[i]))
                {
                    this.Items[i].Index = i;
                    continue;
                }
                // if u want to support duplicates create a nextIndexOf and start searching from i
                var previousIndex = IndexOf(sorted[i]);
                Move(previousIndex, i);
            }
        }

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

        protected override void RemoveItem(int index)
        {
            this.Items[index].ParentCollection = null;
            base.RemoveItem(index);
        }

        protected override void ClearItems()
        {
            foreach (var item in this.Items)
                item.ParentCollection = null;
            base.ClearItems();
        }

        protected override void SetItem(int index, T item)
        {
            this.Items[index].ParentCollection = null;
            item.Index = index;
            item.ParentCollection = this;
            base.SetItem(index, item);
        }

        protected override void MoveItem(int oldIndex, int newIndex)
        {
            this.Items[oldIndex].Index = newIndex;
            this.Items[newIndex].Index = oldIndex;
            base.MoveItem(oldIndex, newIndex);
        }
    }

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

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

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

        public ISortableCollection ParentCollection { get; set; }

        public int CompareTo(object obj)
        {
            return CompareTo(obj as BaseClass);
        }

        public int CompareTo(BaseClass other)
        {
            if (other == null)
                return 1;
            return this.Index.CompareTo(other.Index);
        }
    }

    public class DerivedClass : BaseClass { }

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

        public Controller()
        {
            //do things
            MyDerivedSortableList.Add(new DerivedClass());
            MyDerivedSortableList.Add(new DerivedClass());
            var derivedThing = new DerivedClass();
            MyDerivedSortableList.Add(derivedThing);
            var sibiling = derivedThing.ParentCollection[derivedThing.Index - 1] as BaseClass;  //way easier
            // switch the two objects order and call sort
            // calling a sort before the operation if indexes have been messed with
            // add an event to ISortable to notify the list the index has been changed and mark the list dirty
            derivedThing.Index -= 1;
            sibiling.Index += 1;
            derivedThing.ParentCollection.Sort();   // maybe the list was created where i couldn't access it
        }
    }
}