简体   繁体   English

如何在C#中正确设计具有其非泛型对应项的泛型接口?

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

I have the following code snippet: 我有以下代码片段:

 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 {
  }

Basically the request I have is I want to be able to substitute any IRepository<BackupType> for IRepository, in case I want to put some IRepository<BackupType> into a collection (so I can specify a type for the collection). 基本上,我的请求是我希望能够将任何IRepository <BackupType>替换为IRepository,以防万一我想将一些IRepository <BackupType>放入集合中(以便为该集合指定一种类型)。 I addition to that it seems reasonable and logical to assume IRepository<BackupType> inherits from IRepository (and not the other way around). 除此以外,假设IRepository <BackupType>继承自IRepository似乎是合理且合乎逻辑的(而不是相反)。 Also I definitely want IRepository to have all the properties and methods of IRepository<BackupType> (the only difference being non-generic vs generic) 我也绝对希望IRepository具有IRepository <BackupType>的所有属性和方法(唯一的区别是非通用与通用)

Unfortunately, the compiler gives the following error with the code: 不幸的是,编译器给出了以下错误代码:

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

So I try again with some other code which eliminates this error (IRepositoryBase<> interface is gone): 因此,我尝试使用其他一些代码消除该错误(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);
  }

Now I have these ugly "new"'s in there. 现在我有了这些丑陋的“新”。 Futhermore, upon implementing IRepository<BackupType>, the compiler still seems to want both "Backups" properties implemented, although I hid the first one with "new". 此外,在实现IRepository <BackupType>时,尽管我用“ new”隐藏了第一个属性,但编译器似乎仍希望同时实现“ Backups”属性。

Can somebody tell me how to do this properly? 有人可以告诉我如何正确执行此操作吗? :) :)

If you look at how Microsoft implemented List<T> you'd see that they did not inherit the interface. 如果您查看Microsoft如何实现List<T>您会发现它们没有继承该接口。 The only reason you can treat a List<T> as both an IList and a IList<T> is because List<T> implements both of them. 您可以将List<T>视为IListIList<T>的唯一原因是因为List<T>实现了这两者。

What you probably want is to implement the non-generic interface explicitly . 您可能想要的是显式实现非通用接口。 Here is the difference between an implicit and explicit implementation: 这是隐式和显式实现之间的区别:

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

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

Explicit interface implementation is hidden in the assembly metadata and inaccessible unless you first cast the instance to the appropriate interface type. 除非您首先将实例转换为适当的接口类型,否则显式接口实现将隐藏在程序集元数据中并且无法访问。 You would just have your explicit implementations wrap and call the implicit ones since the types are most likely compatible. 因为类型很可能是兼容的,所以您只需对显式实现进行包装并调用隐式实现。

But I don't think you can achieve your goal of only implementing a member once for two interfaces. 但是我认为您无法实现只为两个接口实现一次成员的目标。

Is this what you want to achieve? 这是您要达到的目标吗?

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)
    }

But if u will have a class which implements both interfaces, you have to implement them explicitly as I don't believe type system will be able to infer conversions for underlying collection. 但是,如果您将拥有一个实现两个接口的类,则您必须显式实现它们,因为我不相信类型系统将能够推断基础集合的转换。

List<IBackup> can hold all IBackup and BackupType, however in that case you cannot just simple cast it to IEnumerable<BackupType> (as there is maybe BackupType2 type in the List which cannot be converted to BackupType) List<BackupType> can be safely converted to IEnumerable<IBackup>, however you cannot just add IBackup to it (for the same reason as above). List <IBackup>可以容纳所有IBackup和BackupType,但是在这种情况下,您不能简单地将其强制转换为IEnumerable <BackupType>(因为List中可能存在BackupType2类型,无法将其转换为BackupType)List <BackupType>可以很安全转换为IEnumerable <IBackup>,但是您不能仅将IBackup添加到其中(与上述相同的原因)。

If you go with: 如果您选择:

  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 
  {
  }

the compiler won't complain. 编译器不会抱怨。

You will still have to implement six members instead of three everytime, some of them by explicit interface implementation. 您仍将必须实现六个成员,而不是每次都实现三个成员,其中一些是通过显式接口实现的。 I have no solution for that. 我对此没有解决方案。

It is the same when you implement genereic IEnumerable<> and have to supply two GetEnumerator methods because you also inherit non-generic IEnumerable . 实现通用IEnumerable<>并必须提供两个GetEnumerator方法的情况相同,因为您还继承了非通用IEnumerable

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM