通用接口中的协方差 [英] Covariance in generic interfaces

查看:80
本文介绍了通用接口中的协方差的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个可排序
的observableCollection,所以我开始创建一个继承可观察性的类,并使用一些方法对其进行排序,然后我希望该类将索引持久化到子类中,因此我创建了一个接口暴露了我可以写的索引属性,并且我将集合类的T强制设置为我的Interface,然后我希望能够从每个项目访问parentCollection,而这里的问题就开始了,因为父类的类型集合是通用的...
我已经尝试了许多解决方案,并且我认为协方差或不变性是方法,但是我无法使其正常工作...

I wanted to create an observableCollection that is sortable so i started creating a class that inherit observable with some methods to sort it, then i wanted that class to persist the index into the childs, so i created an interface that expose an index property where i can write to, and i costrainted the T of my collection class to be of my Interface, then i wanted to be able from avery item to access the parentCollection and here the problems started because the type of the parent collection is generic ... i've tried many solutions, and i think covariance or invariance is the way, but i can't get it working ...

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> ,但是类型不匹配...这是正确的做法吗?

this is more or less the setup. I'd like to be able to create a SortableCollection<DerivedClass> but the types mismatch... wich is the correct way of doing it ?

确切的错误是


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

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>

The problem is that your constraint on T is "T is required to be an I<T>", and you have passed a DerivedClass for T, but DerivedClass is not convertible to I<DerivedClass>, it is convertible to I<BaseClass>.

我不知道您要代表什么 T I< T> 的约束。我确实知道人们经常使用这种模式来表示C#类型系统实际上未实现的约束。详情请参阅我的文章:

I don't know what you are trying to represent with the constraint that T be an I<T>. I do know that people often use this pattern to try to represent a constraint that the C# type system does not actually implement. See my article on the subject for details:

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

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

I encourage you to simplify things considerably; you seem to be trying to capture too much in the type system.

I< D> 的原因是无法转换为 I 的原因是,为了使差异起作用,必须将接口标记为支持差异;将 T 标记为 out in ,具体取决于您是否

The reason why I<D> is not convertible to I<B> is because in order for variance to work, the interface must be marked as supporting variance; mark the T with out or in depending on whether you want covariance or contravariance.

但是,由于 IList< T> 是不变的,因此将其合法化是不合法的派生的接口是协变的还是协变的。考虑使用 IEnumerable< T> ,因为它在 T 中是协变的。

However, since IList<T> is invariant, it will not be legal to make the derived interface covariant or contravariant. Consider IEnumerable<T> instead, as it is covariant in T.

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

In order for an interface to be covariant in T it needs to only use T in output positions. List<T> uses T in both input and output positions, so it cannot be covariant or contravariant.

这篇关于通用接口中的协方差的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆