簡體   English   中英

如何在C#中正確設計具有其非泛型對應項的泛型接口?

[英]How to design generic interface with its non-generic counterpart correctly in C#?

我有以下代碼片段:

 interface IRepositoryBase<BackupType> where BackupType : IBackup {
    IEnumerable<BackupType> Backups { get; set; }
    void Delete(BackupType backup);
    BackupType GetOrCreateBackup(IFileSource source);
  }

  interface IRepository : IRepositoryBase<IBackup> {
  }

  interface IRepository<BackupType> : IRepository, IRepositoryBase<BackupType> where BackupType : IBackup {
  }

基本上,我的請求是我希望能夠將任何IRepository <BackupType>替換為IRepository,以防萬一我想將一些IRepository <BackupType>放入集合中(以便為該集合指定一種類型)。 除此以外,假設IRepository <BackupType>繼承自IRepository似乎是合理且合乎邏輯的(而不是相反)。 我也絕對希望IRepository具有IRepository <BackupType>的所有屬性和方法(唯一的區別是非通用與通用)

不幸的是,編譯器給出了以下錯誤代碼:

IRepository<BackupType> cannot implement both IRepositoryBase<IBackup> and IRepositoryBase<BackupType> because they may unify for some type parameter substitutions

因此,我嘗試使用其他一些代碼消除該錯誤(IRepositoryBase <>接口不見了):

  interface IRepository {
    IEnumerable<IBackup> Backups { get; set; }
    void Delete(IBackup backup);
    IBackup GetOrCreateBackup(IFileSource source);
  }

  interface IRepository<BackupType> : IRepository where BackupType : IBackup {
    new IEnumerable<BackupType> Backups { get; set; }
    void Delete(BackupType backup);
    new BackupType GetOrCreateBackup(IFileSource source);
  }

現在我有了這些丑陋的“新”。 此外,在實現IRepository <BackupType>時,盡管我用“ new”隱藏了第一個屬性,但編譯器似乎仍希望同時實現“ Backups”屬性。

有人可以告訴我如何正確執行此操作嗎? :)

如果您查看Microsoft如何實現List<T>您會發現它們沒有繼承該接口。 您可以將List<T>視為IListIList<T>的唯一原因是因為List<T>實現了這兩者。

您可能想要的是顯式實現非通用接口。 這是隱式和顯式實現之間的區別:

// Implicit
public IEnumerable<TapeBackup> Types { get; set; }

// Explicit
IEnumerable<IBackup> IRepository.Types { get; set; }

除非您首先將實例轉換為適當的接口類型,否則顯式接口實現將隱藏在程序集元數據中並且無法訪問。 因為類型很可能是兼容的,所以您只需對顯式實現進行包裝並調用隱式實現。

但是我認為您無法實現只為兩個接口實現一次成員的目標。

這是您要達到的目標嗎?

internal class BackupType : IBackup { }

    internal interface IFileSource { }

    internal interface IBackup { }

    interface IRepository<TBackup> where TBackup : IBackup
    {
        IEnumerable<TBackup> Backups { get; set; }
        void Delete(TBackup backup);
        TBackup GetOrCreateBackup(IFileSource source);
    }

    interface IRepository : IRepository<IBackup> { }
    interface IRepositoryBackupType : IRepository<BackupType> { }

    class RepositoryBackupType:IRepository,IRepositoryBackupType
    {
    ... (implementation of both interfaces)
    }

但是,如果您將擁有一個實現兩個接口的類,則您必須顯式實現它們,因為我不相信類型系統將能夠推斷基礎集合的轉換。

List <IBackup>可以容納所有IBackup和BackupType,但是在這種情況下,您不能簡單地將其強制轉換為IEnumerable <BackupType>(因為List中可能存在BackupType2類型,無法將其轉換為BackupType)List <BackupType>可以很安全轉換為IEnumerable <IBackup>,但是您不能僅將IBackup添加到其中(與上述相同的原因)。

如果您選擇:

  interface IRepositoryBase<TBackup> where TBackup : IBackup 
  {
    IEnumerable<TBackup> Backups { get; set; }
    void Delete(TBackup backup);
    TBackup GetOrCreateBackup(IFileSource source);
  }

  interface IRepository
  {
    IEnumerable<IBackup> Backups { get; set; }
    void Delete(IBackup backup);
    IBackup GetOrCreateBackup(IFileSource source);
  }

  interface IRepository<TBackup> : IRepositoryBase<TBackup>, IRepository where TBackup : IBackup 
  {
  }

編譯器不會抱怨。

您仍將必須實現六個成員,而不是每次都實現三個成員,其中一些是通過顯式接口實現的。 我對此沒有解決方案。

實現通用IEnumerable<>並必須提供兩個GetEnumerator方法的情況相同,因為您還繼承了非通用IEnumerable

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM