我有以下代码段:
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&lt; BackupType&gt;对于IRepository,如果我想放一些IRepository&lt; BackupType&gt;到集合(所以我可以指定集合的类型)。除此之外,假设IRepository&lt; BackupType&gt;似乎是合理和合乎逻辑的。继承自IRepository(而不是相反)。另外,我绝对希望IRepository拥有IRepository&lt; BackupType&gt;的所有属性和方法。 (唯一的区别是非通用与通用)
不幸的是,编译器在代码中给出了以下错误:
IRepository<BackupType> cannot implement both IRepositoryBase<IBackup> and IRepositoryBase<BackupType> because they may unify for some type parameter substitutions
所以我再尝试一些其他代码来消除这个错误(IRepositoryBase&lt;&gt;接口消失了):
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&lt; BackupType&gt;时,编译器似乎仍然希望实现两个“备份”属性,尽管我用“新”隐藏了第一个属性。
有人可以告诉我如何正确地做到这一点吗? :)
答案 0 :(得分:3)
如果你看一下Microsoft如何实现List<T>
,你会发现他们没有继承该接口。将List<T>
同时视为IList
和IList<T>
的唯一原因是因为List<T>
实现了这两者。
您可能希望实现非通用接口显式。以下是隐式和显式实现之间的区别:
// Implicit
public IEnumerable<TapeBackup> Types { get; set; }
// Explicit
IEnumerable<IBackup> IRepository.Types { get; set; }
显式接口实现隐藏在程序集元数据中且无法访问,除非您首先将实例强制转换为适当的接口类型。您只需将显式实现换行并调用隐式实现,因为类型很可能是兼容的。
但我认为你不能实现只为两个接口实现一次成员的目标。
答案 1 :(得分:0)
这是你想要达到的目标吗?
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)
}
但是如果你有一个实现两个接口的类,你必须明确地实现它们,因为我不相信类型系统能够推断底层集合的转换。
列表与LT; IBACKUP&GT;可以保存所有IBackup和BackupType,但是在这种情况下,您不能简单地将其转换为IEnumerable&lt; BackupType&gt; (因为List中可能有BackupType2类型,无法转换为BackupType) 列表与LT; BackupType&GT;可以安全地转换为IEnumerable&lt; IBackup&gt;,但是你不能只为它添加IBackup(出于与上述相同的原因)。
答案 2 :(得分:0)
如果你选择:
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
{
}
编译器不会抱怨。
您仍然需要每次实现六个成员而不是三个成员,其中一些是通过显式接口实现。我没有解决方法。
当您实施genereic IEnumerable<>
时必须提供两个GetEnumerator
方法,因为您还继承了非通用IEnumerable
。