c# - 通用接口(interface)中的协变

标签 c# .net generics variance

我想创建一个可排序的 observableCollection 所以我开始创建一个继承 observable 的类,并使用一些方法对其进行排序,然后我希望该类将索引持久保存到子项中,所以我创建了一个接口(interface),该接口(interface)公开了一个我可以写入的索引属性,并且我限制了 T我的集合类是我的接口(interface),然后我希望能够从每个项目访问 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
        }
    }
}

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

准确的错误是

Error 1 The type 'ClassLibrary1.DerivedClass' cannot be used as type parameter 'T' in the generic type or method 'ClassLibrary1.SortableCollection<T>'. There is no implicit reference conversion from 'ClassLibrary1.DerivedClass' to 'ClassLibrary1.ISortable<ClassLibrary1.DerivedClass>'. c:\users\luigi.trabacchin\documents\visual studio 2013\Projects\ClassLibrary1\ClassLibrary1\Class1.cs 48 89 ClassLibrary1

最佳答案

问题是你对 T 的约束是“T 必须是 I<T> ”,并且您已通过 DerivedClass对于 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>是因为为了使变体起作用,必须将接口(interface)标记为支持变体;标记 Toutin取决于您是想要协变还是逆变。

但是,由于 IList<T>是不变的,使派生接口(interface)协变或逆变都是不合法的。考虑 IEnumerable<T>相反,因为它在 T 中是协变的.

为了使接口(interface)在 T 中是协变的它只需要使用 T输出位置。 List<T>使用 T在输入和输出位置,所以它不能协变或逆变。

关于c# - 通用接口(interface)中的协变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29447867/

相关文章:

c# - 在缺少 setup.py 的 Windows 上构建 Apache QPID

c# - 无法将属性或索引器 'string.this[int]' 分配给 -- 它是只读的

c# - 使用 MVVM 获取 WPF 中的 Textblock 以进行更新

java - 什么是原始类型,为什么我们不应该使用它呢?

java - 从 JAXB 泛型中删除 xsi :type, xmlns :xs, 和 xmlns:xsi

typescript - 如何在 TypeScript 中将类型参数设置为 "nothing"?

c# - 单用户访问数据库的建议

c# - 将 List<string> 添加到 DataTable

c# - 增加 ServicePointManager.DefaultConnectionLimit 的缺点

c# - 在 ListView 的特定列中搜索