2014-06-23 100 views
4

我試圖模擬我可以在Ninject中配置的行爲,僅使用Unity代替。在基於混合類型的Unity中註冊泛型Type

我試圖使用緩存的存儲庫模式,給出以下類和接口:

public interface IRepository<T> 
{ 
    T Get(); 
} 

public class SqlRepository<T> : IRepository<T> 
    where T : new() 
{ 
    public T Get() 
    { 
     Console.WriteLine("Getting object of type '{0}'!", typeof(T).Name); 
     return new T(); 
    } 
} 

public class CachedRepository<T> : IRepository<T> 
    where T : class 
{ 
    private readonly IRepository<T> repository; 

    public CachedRepository(IRepository<T> repository) 
    { 
     this.repository = repository; 
    } 

    private T cachedObject; 
    public T Get() 
    { 
     if (cachedObject == null) 
     { 
      cachedObject = repository.Get(); 
     } 
     else 
     { 
      Console.WriteLine("Using cached repository to fetch '{0}'!", typeof(T).Name); 
     } 
     return cachedObject; 
    } 
} 

基本上,我的應用程序使用IRepository<T>任何時候,都應該得到的CachedRepository<T>一個實例。但是在CachedRepository<T>之內,它應該獲取SqlRepository<T>的實際SQL存儲庫。在Ninject中,我已經完成了這個使用以下內容:

ninjectModule.Bind(typeof(IRepository<>)).To(tyepof(SqlRepository<>)).WhenInjectedExactlyInto(tyepof(CachedRepository<>)); 
ninjectModule.Bind(typeof(IRepository<>)).To(tyepof(CachedRepository<>)); 

在Unity中,我將如何完成同樣的事情?我對非通用庫版本的作品:

UnityContainer container = new UnityContainer(); 
container.RegisterType<IWidgetRepository, CachedWidgetRepository>(new InjectionMember[] { new InjectionConstructor(new SqlWidgetRepository()) }); 

但是這句法將無法使用通用的倉庫處的所有工作,因爲你不能說new SqlRepository<>無需語法錯誤。有任何想法嗎?

+0

相關:https://stackoverflow.com/questions/9813630/how-to-do-open-generic-decorator-chaining-with-unity-unityautoregistration – Steven

回答

5

假設你不想註冊每一個人可以通用的,就像這樣:

container.RegisterType<IRepository<Things>, CachedRepository<Things>>(new InjectionMember[] {new InjectionConstructor(new SqlRepository<Things>())}); 

container.RegisterType<IRepository<OtherThings>, CachedRepository<OtherThings>>(new InjectionMember[] {new InjectionConstructor(new SqlRepository<OtherThings>())}); 

你也可以使用一個定製注塑廠,這是他說的這樣一種有趣的方式「寫自己的工廠函數「。

// We will ask Unity to make one of these, so it has to resolve IRepository<Things> 
public class UsesThings 
{ 
    public readonly IRepository<Things> ThingsRepo; 

    public UsesThings(IRepository<Things> thingsRepo) 
    { 
     this.ThingsRepo = thingsRepo; 
    } 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     var container = new UnityContainer(); 

     // Define a custom injection factory. 
     // It uses reflection to create an object based on the requested generic type. 
     var cachedRepositoryFactory = new InjectionFactory((ctr, type, str) => 
      { 
       var genericType = type.GenericTypeArguments[0]; 
       var sqlRepoType = typeof (SqlRepository<>).MakeGenericType(genericType); 
       var sqlRepoInstance = Activator.CreateInstance(sqlRepoType); 
       var cachedRepoType = Activator.CreateInstance(type, sqlRepoInstance); 
       return cachedRepoType; 
      }); 

     // Register our fancy reflection-loving function for IRepository<> 
     container.RegisterType(typeof(IRepository<>), typeof(CachedRepository<>), new InjectionMember[] { cachedRepositoryFactory }); 

     // Now use Unity to resolve something 
     var usesThings = container.Resolve<UsesThings>(); 
     usesThings.ThingsRepo.Get(); // "Getting object of type 'Things'!" 
     usesThings.ThingsRepo.Get(); // "Using cached repository to fetch 'Things'!" 
    } 
}