C# 强制泛型参数的类型为接口而不是特定类

C# 强制泛型参数的类型为接口而不是特定类,c#,generics,C#,Generics,给定这些接口和实现 interface IService {} class Service : IService {} 用一般方法 void Register<I>(I service) { var type = typeof(I); } void寄存器(I服务) { 变量类型=类型(I); } 关于泛型类型,如何使以下行保持一致 Register<IService>(new Service()) // type is 'IService' Regis

给定这些接口和实现

interface IService {}
class Service : IService {}
用一般方法

void Register<I>(I service)
{
    var type = typeof(I);
}
void寄存器(I服务)
{
变量类型=类型(I);
}
关于泛型类型,如何使以下行保持一致

Register<IService>(new Service())    // type is 'IService'
Register(new Service());             // type is 'Service'
Register(new Service())//类型为'IService'
注册(新服务());//类型为“服务”
可接受两种选择:

  • 这两行都是使用IServie类型编译的
  • 第二行无法编译

    • 您的意思是将
      I
      的类型限制为
      iSeries设备,对吗

      使用泛型类型:

      void Register<TServiceType>(TServiceType service)
          where TServiceType : IService
      
      无效寄存器(TServiceType服务)
      其中TServiceType:IService
      

      如果您要求的是将参数限制为任何接口,那么,正如Jon所述(但为了减少我的答案的冗余),这是非法的。

      您不能-无法将类型参数限制为接口


      当然,您可以执行执行时间检查,如果
      I
      不是接口,则抛出异常。(另一方面,命名约定建议这应该是
      T
      ,而不是
      I

      正如您所注意的,
      注册(新服务())当然编译到
      寄存器(新服务())

      假设您可以定义一些逻辑来选择具体类型的一个实现接口作为要注册的接口(这是一个很大的假设),那么您可以处理具体类型,而不是让编译器排除它们。显然,简单的解决方案是要求类型只实现一个接口,但这不太可能非常有用

      我考虑了以下几点(采纳Jon Skeet的建议并重命名类型参数):

      然而,即使不调用对象上的任何接口成员,泛型还有另一个好处:编译时类型检查。有没有办法在强制开发人员显式指定类型的同时进行编译时类型检查?是:方法签名中有两个类型参数,但只有一个参数,编译器无法推断这两种类型,因此开发人员必须同时提供这两种类型。这需要更多的输入,但代码更明确

      通过这种方法,您还可以将实现类型约束为接口类型,以确保开发人员不会调用,例如,
      Register(newsecurityservice())

      接口IServiceBase{}//所有服务接口必须实现的接口;可能不需要
      接口IService:IServiceBase{}
      类服务:IService:{}
      无效寄存器(TImplementingObject服务)
      其中TServiceType:IServiceBase//如果没有IServiceBase,当然是多余的
      其中TimplementObject:t服务类型
      {
      //…实施
      }
      //用法:
      void InitializeServices()
      {
      注册(新服务());
      }
      
      甚至

      class NewImprovedService : Service : { }
      
      void InitializeServices()
      {
          Register<IService, Service>(new NewImprovedService());
      }
      
      classnewimprovedservice:Service:{}
      void InitializeServices()
      {
      注册(NewImprovedService());
      }
      
      这让我们回到了一些可能冗余的类型指示的问题上,调用甚至比您开始时更详细,但它确实防止了开发人员无意中注册错误的服务类型

      然而,我们仍然有最初的问题,因为没有什么可以阻止开发人员调用

      Register<Service, NewImprovedService>(new NewImprovedService());
      
      注册(NewImprovedService());
      

      在运行时检查
      typeof(TServiceType)之前,这不会失败。IsInterface

      这将允许实现接口的所有类型我认为您误解了这个问题。我相信这样做的目的是将
      I
      约束为一个接口——任何接口——而不是一个具体的类。@JonSkeet Me误解可能是有道理的。我会暂时保留这个,直到我们发现其他情况,以防万一。但你可能是对的。如果是这样的话,我不知道你想用它做什么。@sil:不确定-我似乎记得另一个问题,关于使用代码契约的这类事情,它不起作用-但我可能是错的。可能重复我同意Register(new Service())是最清晰的形式。但是我如何强制程序员不忽略
      ?例如,Re sharper可能表示
      是多余的。@ReuvenBass这是一个很好的观点。有关更多想法,请参见编辑后的答案。
      interface IServiceBase { } // interface that all service interfaces must implement; might not be needed
      interface IService : IServiceBase { }
      class Service : IService : { }
      
      void Register<TServiceType, TImplementingObject>(TImplementingObject service)
          where TServiceType : IServiceBase  // superfluous if there's no IServiceBase, of course
          where TImplementingObject : TServiceType
      {
          // ... implementation
      }
      
      //usage:
      void InitializeServices()
      {
          Register<IService, Service>(new Service());
      }
      
      class NewImprovedService : Service : { }
      
      void InitializeServices()
      {
          Register<IService, Service>(new NewImprovedService());
      }
      
      Register<Service, NewImprovedService>(new NewImprovedService());