2016-02-27 64 views
0

由於泛型接口,我想要解析開放式泛型服務。我使用autofac。使用Autofac註冊並解析具有許多通用參數的開放式泛型類型

每個具體的服務只適用於具體的類。

我只能用一個generic param解決一個服務[見SingleOpenGenericResolveTest]。是否可以註冊&解決許多服務與許多T-params [見MultiOpenGenericResolveTest]?

我只爲IService添加了一個具體類,但它可能是許多類T。 (TRegion : Region, TRegion : BigRegion,等...)

下面是NUnit的3次測試,或者你可以在這裏下載我的解決方案:https://www.dropbox.com/s/vqmdwb6hwmzgjrb/AutofacResolveTests.zip?dl=0

using System; 
using NUnit.Framework; 
using Autofac; 
using System.Reflection; 
using System.Linq; 

namespace AutofacResolveTests 
{ 
    public class Address<TCity, TRegion, TSomethingElse> 
     where TCity : City<TRegion>, new() 
     where TRegion : Region, new() 
     where TSomethingElse : SomethingElse, new() 
    { 
     public int Id { get; set; } 
     TCity City { get; set; } 
     TRegion Region { get; set; } 
     TSomethingElse SomethingElse { get; set; } 
    } 

    public class City<TRegion> 
     where TRegion : Region, new() 
    { 
     public int Id { get; set; } 
     TRegion Region { get; set; } 
    } 

    public class Region 
    { 
     public int Id { get; set; } 
    } 

    public class SomethingElse 
    { 
     public int Id { get; set; } 
    } 

    public interface IService<T> where T : class 
    { 
     void DoSomething(T entity); 
    } 

    public class AddressService<TAddress, TCity, TRegion, TSomethingElse> : IService<TAddress> 
     where TAddress : Address<TCity, TRegion, TSomethingElse> 
     where TCity : City<TRegion>, new() 
     where TRegion : Region, new() 
     where TSomethingElse : SomethingElse, new() 
    { 
     public void DoSomething(TAddress entity) 
     { 
      Console.WriteLine("Hello from address service"); 
     } 
    } 

    public class CityService<TCity, TRegion> : IService<TCity> 
     where TCity : City<TRegion>, new() 
     where TRegion : Region, new() 
    { 
     public void DoSomething(TCity entity) 
     { 
      Console.WriteLine("Hello from city service"); 
     } 
    } 

    public class RegionService<TRegion> : IService<TRegion> 
     where TRegion : Region 
    { 
     public void DoSomething(TRegion entity) 
     { 
      Console.WriteLine("Hello from region service"); 
     } 
    } 

    [TestFixture] 
    public class OpenGenericResolveTests 
    { 
     IContainer _ioc; 

     [SetUp] 
     public void Setup() 
     { 
      var container = new ContainerBuilder(); 
     //manual types registration - works 
     /* 
     container.RegisterType(typeof(CityService<City<Region>, Region>)).As(typeof(IService<City<Region>>)).AsImplementedInterfaces(); 
     container.RegisterType(typeof(AddressService< 
      Address<City<Region>, Region, SomethingElse>, City<Region>, Region, SomethingElse 
      >)) 
      .As(typeof(IService< 
      Address<City<Region>, Region, SomethingElse> 
      >)).AsImplementedInterfaces(); 
     */ 

      var type = typeof(IService<>); 
      //just get all services which implements IService 
      var generics = type.Assembly.GetTypes().Where(x => 
      !x.IsInterface 
      && x.Name.Contains("Service") 
      && x.IsGenericType 
      && x.GetInterfaces().Any(i => i.GetGenericTypeDefinition() == type) 
      ); 

      foreach (var svcType in generics) 
      { 
       container.RegisterGeneric(svcType) 
       .As(typeof(IService<>)) 
       .AsImplementedInterfaces(); 
      } 

      _ioc = container.Build(); 
     } 

     [Test] 
     public void SingleOpenGenericResolveTest() 
     { 
      var reg = new Region { }; 

      var actual = _ioc.Resolve<IService<Region>>(); 
      Assert.That(actual != null); 

      actual.DoSomething(reg); 
     } 

     [Test] 
     public void MultiOpenGenericResolveTest() 
     { 
      //works 
      var actual1 = _ioc.Resolve<IService<Region>>(); 
      Assert.That(actual1 != null); 

      //works only with manual registration 
      var actual2 = _ioc.Resolve<IService<City<Region>>>(); 
      Assert.That(actual2 != null); 

      //works only with manual registration 
      var actual3 = _ioc.Resolve<IService<Address<City<Region>,Region,SomethingElse>>>(); 
      Assert.That(actual3 != null); 
     } 
    } 
} 

回答

0

的問題是,如果你解決IService<T>但執行時間超過一個普通的像那麼Autofac無法知道其他類型(U,V)來自何處......因此,您嘗試使用程序集掃描進行註冊的方式將無法工作。

+0

好的。我理解它。但是可能有可能通過根類型(TCity:City)找到所有類型(TRegion:Region),並在Autofac中使用反射或某個事件註冊服務:OnActivating,OnPreparing ...? –