[英]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>
視為IList
和IList<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.