【问题标题】:Inheriting an interface with a List<Interface> as a property problems继承具有 List<Interface> 的接口作为属性问题
【发布时间】:2012-08-22 20:46:26
【问题描述】:

我有两个接口,一个包含另一个接口的列表,我想要一个实现第一个接口的类,但有一个实现第二个接口的另一个类的列表,而不仅仅是一个接口列表。示例:

namespace TestInheritance
{
    public interface IBookShelf
    {
        long Stuff { get; set; }
        List<IBook> Books { get; set; }
    }
    public interface IBook
    {
        string Name { get; set; }
    }
    public class BookShelf : IBookShelf
    {
        public long Stuff { get; set; }
        public List<Book> Books { get; set; }
    }
    public class Book : IBook
    {
        public string Name { get; set; }
    }
}

显然它不喜欢这样。有没有正确的方法来做我想做的事情,还是我只需要让BookShelf 有一个List&lt;IBook&gt; 并在我想使用它时将每个IBook 转换为Book?在这里寻找可以帮助我的模式。谢谢。

【问题讨论】:

  • 仅供参考,您实现了一个接口,而不是继承它。
  • ……除非你是另一个接口
  • @Jay 好吧,你让我到了那里。
  • @asawyer 好电话。不过我的问题是对的!

标签: c# .net list interface


【解决方案1】:

您可以将IBookShelf 设为泛型,将泛型参数限制为IBook

那么你可以:

public interface IBookShelf<T> where T : IBook
{
    long Stuff { get; set; }
    List<T> Books { get; set; }
}

public class BookShelf : IBookShelf<Book>
{
    public long Stuff { get; set; }
    public List<Book> Books { get; set; }
} 

【讨论】:

  • 这是正确的(也是显示此解决方案的第一个答案)。
  • @Jay 是的,它非常接近我正在寻找的东西。我真正需要的是能够在一个地方将 IBookShelf 的图书列表作为 List 引用,在另一个地方作为 List 引用。这有意义吗?
  • @Biojayc 我认为如果您需要 List&lt;IBook&gt;List&lt;Book&gt; 在其中一种情况下,您必须使用您的解决方案或我的解决方案。您能否在您的问题中添加一些用法示例,以使您的问题更清晰?
【解决方案2】:

不清楚您想要做什么——我怀疑你甚至不清楚。为什么你特别希望BookShelf.Books 成为List&lt;Book&gt;?为什么 限制 本身只包含 Book 值而不是 IBook 值?我建议你考虑一下在这种情况下你希望发生什么:

public class EvilBook : IBook
{
    public string Name { get; set; }
}

IBookShelf bookShelf = new BookShelf() { Books = new List<Book>() };
bookShelf.Books.Add(new EvilBook());

该代码中没有任何可疑之处1,使用您提供的接口 - 但它最终将 EvilBook 添加到 List&lt;Book&gt; 中,这肯定是不正确的。我经常发现,如果编译器阻止我做某事,那么想想如果它让我继续我的坏主意我可能会遇到什么问题是很有用的。

您可能希望考虑IBookShelf 设为通用:

public interface IBookShelf<T> where T : IBook
{
    long Stuff { get; set; }
    List<T> Books { get; set; }
}

然后:

public class BookShelf : IBookShelf<Book>

...但这实际上取决于您要达到的目标。

您可能还想首先问自己是否真的需要IBook 接口......以及您是否真的想要Books 的公共可写 属性。


1 无论如何,编译器会识别:)

【讨论】:

  • “该代码中没有任何可疑之处” 我个人认为任何以“Evil”为前缀的类名都是可疑的。不过我想我过于敏感了。
  • @Servy:适当添加脚注:)
【解决方案3】:

这样的事情怎么样:

namespace TestInheritance
{
    public interface IBookShelf <TBook> where TBook : IBook
    {
        long Stuff { get; set; }
        List<TBook> Books { get; set; }
    }
    public interface IBook
    {
        string Name { get; set; }
    }
    public class BookShelf : IBookShelf<Book>
    {
        public long Stuff { get; set; }
        public List<Book> Books { get; set; }
    }
    public class Book : IBook
    {
        public string Name { get; set; }
    }
}

【讨论】:

  • 这与我想要的解决方案非常接近。我需要的是在一个地方只能使用 IBookShelf 和 IBook 接口来引用集合,但在另一个地方使用 BookShelf 和 Book。这有意义吗?
【解决方案4】:
  1. 一般来说,强制转换是可疑的,最好避免。这是一个很好的信号,表明有些事情是不对的。

  2. 要修复您需要更改的代码

    public List<Book> Books { get; set; }
    

    public List<IBook> Books { get; set; }
    
  3. 您可以而且应该更多地概括事物。什么样的书架不能放其他物品?我还没有看到一个。考虑一下:

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
public interface IShelf
{
    long Stuff { get; }
    List<IShelfItem> Items { get; }
}
public interface IShelfItem
{
    string Name { get; }
    string Thought {get; set;}//What do I think about it?
}
public class Shelf : IShelf
{
    public Shelf(long stuff, string color) 
    {
        Stuff = stuff;
        Items = new List<IShelfItem>();
        Color = color;
    }

    public long Stuff { get; private set; }
    public List<IShelfItem> Items { get; private set; }//Note, you can still add to the list.
    public string Color { get; set; }

}
public class Book : IShelfItem
{
    public Book( string name, string thought ) {
        Name = name;
        Thought = thought;
    }
    public string Name { get; private set; }//Books that are on shelves don't really change their name;
    public string Thought { get; set; }

    public string BookSpecificProperty { get; set; }
}


public static void Main()
{
    Shelf myShelf = new Shelf(42, "Dull boring grey");

    myShelf.Color = "Red";


    IShelf myIShelf = myShelf;
    //myIShelf.Color = "Red"; - 'IShelf' does not contain a definition for 'Color'

    myShelf.Items.Add( new Book("Title 1", "Such a great book" ) );

    //Eos pass

    var book = myShelf.Items.SingleOrDefault( i => i.Name == "Title 1" );
    if( book != null ) {
        book.Thought = "I used to think it was such a great book. It's just OK";
        //book.BookSpecificProperty = "X"; - 'IShelfItem' does not contain a definition for 'BookSpecificProperty'
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-10
    • 2011-02-19
    • 2017-05-12
    • 1970-01-01
    相关资源
    最近更新 更多