某些接口的类型有限的泛型C#类没有实现与第一个接口的成员的其他接口

时间:2015-03-30 23:30:08

标签: c# generics interface

我理解为什么要有这样的课时会遇到问题:

public class Section<T> : ISection 
    where T : ISectionItem
{
    public string Title { get; set; }
    public LinkedList<T> Items { get; set; }
}

实现这样的界面:

public interface ISection
{
    string Title { get; set; }
    LinkedList<ISectionItem> Items { get; set; }
}

我收到编译错误说:

Error   1   
'JobTracker.Model.CV.Section<T>' does not implement interface member 
'JobTracker.Model.CV.ISection.Items'. 
'JobTracker.Model.CV.Section<T>.Items' cannot implement 
'JobTracker.Model.CV.ISection.Items' 
because it does not have the matching return type of
'System.Collections.Generic.IEnumerable<JobTracker.Model.CV.ISectionItem>'.

应该可以,因为T保证是ISectionItem类型。可能的解决方案之一可能是使用泛型ISection创建addidiotional或替换ISection<T>,但我不知道当我想要将它与Xaml一起使用时它将如何表现。有没有让编译器知道接口符合要求?

EDIT1:在IEnumerable中将LinkedList更改为ISection,因为这是一个糟糕的概念,而且回答的焦点与我最感兴趣的主题有关。

EDIT2:我的问题更多地针对为什么不允许实施ISectionItem,但我注意到我是多么愚蠢。接口ISection允许在一个列表ISectionItem中使用实现Section<T>的多个不同类。

大家,你的答案都是正确的,但我会将Olivier的标记作为答案,因为它也显示了这个问题的解决方案。

3 个答案:

答案 0 :(得分:2)

符合要求。

考虑以下

Section<ItemX> xSection = new Section<ItemX>;
//xSection.Items = BindingList<ISectionItem>();
ISection xISection = xSection;
xISection.Items = BindingList<ISectionItem>();

界面中的合同是Items可以分配给 ISectionItem的任何集合。

答案 1 :(得分:2)

如果您通过界面访问Items,则可以为其分配一个不是LinkedList<T>的集合,这会导致错误。由于Items也有一个setter,因此它不能是IEnumerable<T>;但是,您可以像这样实现它

private LinkedList<T> _items;
public IEnumerable<T> Items {
    get { return _items; }
    set {
        var linkedList = value as LinkedList<T>;
        if (linkedList != null) {
            _items = linkedList;
        } else {
            _items = new LinkedList<T>(value);
        }
    }
}

要使其正常工作,您必须将界面更改为:

public interface ISection<T>
    where T : ISectionItem
{
    string Title { get; set; }
    IEnumerable<T> Items { get; set; }
}

并声明这个类

public class Section<T> : ISection<T> 
    where T : ISectionItem
{
    ...
}

您的修改无法解决问题。通过您的课程,您可以指定实施LinkedList<T>的任何T ISectionItem;但是,您的界面允许您添加与ISectionItem不同的T

class DerivedA : ISectionItem
{
    ...
}

class DerivedB : ISectionItem
{
    ...
}
ISection s = new Section<DerivedA>();
s.AddLast(new DerivedB()); // The collection in `s` is a `LinkedList<DerivedA>` boom!

故事的寓意是集合项的继承(或者一般来说:某种类型的泛型类型参数)不定义集合的继承。

T'来自T

Collection<T'>来自Collection<T> ==&gt;的假!

这两个集合只是两个不同的集合,没有任何赋值兼容性。

答案 2 :(得分:0)

如果您可以将Items接口属性设置为只读,那么最简单的路由似乎是将显式接口实现添加为重载:

public interface ISection
{
    string Title { get; set; }
    IEnumerable<ISectionItem> Items { get; }
}

public class Section<T> : ISection 
    where T : ISectionItem
{
    public string Title { get; set; }
    public LinkedList<T> Items { get; set; }

    IEnumerable<ISectionItem> ISection.Items
    {
        get {return Items.Cast<ISectionItem>();}
    }
}