【问题标题】:Interfaces inheritance in C#C#中的接口继承
【发布时间】:2011-04-21 20:10:47
【问题描述】:

我试图解决我在编写应用程序时遇到的(对我而言)相当大的问题。 请看这个(为了简单起见,我会尽量缩短代码):

我有一个名为IRepository<T> 的根接口。 接下来,IBookRepository : IRepository<Book> 接下来,实现它的具体类:BookRepository : IBookRepository

在 RepositoryManager 类中我声明了private IRepository<IRepoItem> currentRepo;

IRepoItem是Book类实现的接口。

现在,当我尝试做这样的事情时:

currentRepo = new BookRepository();

VisualStudio 给出错误信息:

无法将类型“BookRepository”隐式转换为“IRepository”。存在显式转换(您是否缺少演员表?)

我尝试显式转换,但抛出运行时异常...

我知道(几乎可以肯定)它是一种称为协方差的东西,这(可能)在 .Net 4.0 中得到了解决。 不幸的是,我正在使用框架版本 3.5 编写,我无法更改这一点。请给我一些建议该怎么做 - 如何解决这个问题?我想从 RepoFactory 获取 currentRepo ,它会根据用户需求生成几种存储库。我不知道这里是否允许链接,但我在http://olgatherer.wordpress.com/ 上写了一些博客,我在其中描述了应用程序的创建。我的英语不好,但我希望它足以理解我。提前感谢您的回答。

最好的问候, skrzeczowas

【问题讨论】:

  • currentRepo 声明的类型是什么?
  • 没关系,我看到它是一个 IRepository。

标签: c# oop interface covariance


【解决方案1】:

在 .NET 3.5 中,您绝对不能将 IRepository<Book> 视为 IRepository<IRepoItem>。

我们需要更多地了解您在 RepositoryManager 中使用存储库的内容,才能真正知道如何解决它...但是您能否创建一个非通用的 IRepository 接口,IRepository<T> 扩展?让它包含所有不引用T的成员。然后你可以将currentRepo声明为IRepository。

【讨论】:

  • +1 - 我想过这个非通用的IRepository 接口,但不确定如何实现它。优秀的乔恩! =)
  • 您好!我有这里描述的存储库:olgatherer.wordpress.com/2010/08/18/repositoriesrus 我创建了 DbManager 来管理数据库并为每个表(书籍、漫画、邮戳等)创建存储库。现在我希望 DbManager 中的 currentRepository 可以是 BookRepository、StampsRepository 等等——我认为这个带有接口的东西可以,但不幸的是不是,因为 IRepoItem(正如我今天意识到的那样)应该有所有不同的属性...... :(
【解决方案2】:

尝试使用中间层(IRp):

    interface IRepository<T>
    {
    }

    interface IRep<T> : IRepository<IRepoItem> where T : IRepoItem
    {
    }

    interface IBookRepository : IRep<Book>
    {
    }

    class BookRepository : IBookRepository
    {
    }

然后你就可以做你想做的事了:

        BookRepository br = new BookRepository();
        IRepository<IRepoItem> currentRepo = br;

【讨论】:

  • 嗨!这很棒而且非常优雅,我很高兴你发布了这个。不幸的是,正如我在上面帖子的评论中所描述的,我意识到这并不完全适合我。 IRepoItem 是一个将在书籍、邮票、漫画中实现的接口,因此它应该具有不同项目的所有属性。这不聪明,我必须找到另一种方法来实现我想要的 - 这意味着我希望 currentRepo 成为 BookRepository 或 StampsRepository 或任何其他存储库......也许有些帮助?
  • IRepoItem 作为其他东西的接口应该只会导致它整合它们共同的东西,而不是“所有属性”。例如 IMoveable 应该只公开 Move 方法,而不是所有从它派生的类(如 Cheetah、Car、Airplane)都有的所有东西。
  • 但是,如果我有 currentRepo = StampsRepo();,我将只能使用 IRepository 包含的方法。我将无法使用 IStampsRepository 方法 :( 我相信我可以问这个 currentRepo 是什么类型: if(currentRepo is IBookRepository)do something else if(currentRepo is IStampsRepository) do something ...但这不是好的对象编程,我想。我必须重新考虑我所做的所有假设,因为也许我想要的是愚蠢且无法实现的......
  • 如果是这种情况,祝你重构好运 ;)
【解决方案3】:

在 .NET 3.5 中,IRepository 和 .NET 4 中的 IRepository 之间没有任何关系,您可以通过协变和逆变支持实现类似的功能(但这取决于 IRepository 接口声明)

A 会建议使用非通用 IRepository 接口并自己进行转换。我知道,这不是很好,但是您描述的功能需要协变/逆变支持。

【讨论】:

  • 感谢您的回答,我在下面使用了这个并意识到这并不完全适合我:(我现在不知道该怎么办... IRepoItem 不能拥有所有属性书籍、漫画、邮票由 :(
猜你喜欢
  • 2023-03-04
  • 1970-01-01
  • 2011-03-24
  • 1970-01-01
  • 2023-03-14
  • 2013-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多