2011-09-06 58 views
1

最近我用IoC工具LightCore玩了一下。自從上一版本以來,沒有任何命名實例被允許,並且支持ServiceLocator模式(?)。如何解析來自LightCore ServiceLocator的命名實例?

我從ServiceLocator中需要的關鍵功能之一是解析命名實例。我的第一個想法是重寫DoGetInstance方法並實現我自己的代碼。

我最後的解決辦法是讓一個實例通過它的類型名稱

_testInstanceKey = "My.Namespace.MyType, MyAssembly"; 
IMyType type = locator.GetInstance(typeof(IMyType), _testInstanceKey) 

protected override object DoGetInstance(Type serviceType, string key) 
{ 
    return _container.ResolveAll(serviceType) 
      .Where(x => x.GetType() == Type.GetType(key,true,true)) 
      .FirstOrDefault(); 
} 

這工作了,但我需要什麼了,如果我硬線我的類型名稱一個服務定位?

有沒有人有任何建議如何解決這個半成熟的ServiceLocator?

+0

服務定位器模式[由定義不完整](http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx)。如果可以,請轉到依賴注入模式。 – Steven

+0

悲傷但真實,我知道Mark Seemann的博客文章。不幸的是,我不能移動,因爲它是使用ServiceLocator的傳統應用程序。 –

+0

你總是可以,但這需要時間。這一天不會發生,這是肯定的。 – Steven

回答

2

您可以通過引入IMyTypeFactory接口,讓應用程序需要在該接口上的依賴關係解決這個問題:

// Factory interface: 
public interface IMyTypeFactory 
{ 
    IMyType GetByName(string name); 
} 

// Implementation in the composition root: 
public class MyTypeFactory : 
    Dictionary<string, Func<IRequestHandler>>, IMyTypeFactory 
{ 
    public IMyType GetByName(string name) { return this[name](); } 
} 

// Registration 
var factory = new MyTypeFactory 
{ 
    { "foo",() => new MyType1() }, 
    { "bar",() => new MyType2() }, 
    { "boo",() => new MyType3() }, 
}; 

builder.Register<IMyTypeFactory>(c => factory); 

正如我在評論說,試圖從使用服務定位器移開反模式。它將改進應用程序的可測試性和可維護性。當使用依賴注入(DI)模式時,不直接調用容器,也無法直接詢問命名實例。應用DI時,您必須更改配置容器的方式,或者需要在應用程序中應用正確的抽象(如IMyTypeFactory所示)。

+0

一般而言,你是完全正確的。可能我誤解了:這是一個內部使用ServiceLocator的應用程序/框架,但我無法更改該代碼。 –

0

假如你不能改變框架調用定位器的方式,假設框架使用通用服務定位器作爲你的容器和自身之間的界面,你可以添加此功能的自定義IServiceLocator實現:

// This adapter wraps the CSL LightCoreAdapter of LightCore itself. 
public class LightCoreServiceLocatorAdapter : IServiceLocator 
{ 
    private readonly LightCoreAdapter container; 

    public LightCoreServiceLocatorAdapter(IContainer container) 
    { 
     // You need a reference to LightCore.CommonServiceLocator.dll. 
     this.container = new LightCoreAdapter(container); 
    } 

    public IEnumerable<TService> GetAllInstances<TService>() 
    { 
     return this.container.GetAllInstances<TService>(); 
    } 

    public IEnumerable<object> GetAllInstances(Type serviceType) 
    { 
     return this.container.GetAllInstances(serviceType); 
    } 

    public TService GetInstance<TService>(string key) 
    { 
     if (key == null) 
     { 
      return this.container.GetInstance<TService>(null); 
     } 
     else 
     { 
      // This is custom logic 
      this.container.GetInstance<INamedFactory<TService>>().GetByKey(key); 
     } 
    } 

    public TService GetInstance<TService>() 
    { 
     return this.container.GetInstance<TService>(); 
    } 

    public object GetInstance(Type serviceType, string key) 
    { 
     if (key == null) 
     { 
      return this.container.GetInstance(serviceType); 
     } 
     else 
     { 
      // This is custom logic 
      var facType = typeof(INamedFactory<>).MakeGenericType(serviceType); 
      var factory = (INamedFactory)this.container.GetInstance(facType); 
      return factory.GetByKey(key); 
     } 
    } 

    public object GetInstance(Type serviceType) 
    { 
     return this.container.GetInstance(serviceType); 
    } 

    object IServiceProvider.GetService(Type serviceType) 
    { 
     ((IServiceProvider)this.container).GetService(serviceType); 
    } 
} 

此類使用以下兩種自定義接口:

public interface INamedFactory 
{ 
    object GetByKey(string key); 
} 

public interface INamedFactory<T> : INamedFactory 
{ 
    T GetByKey(string key); 
} 

使用這種定製LightCoreServiceLocatorAdapter這兩個自定義界面,您可以創建自定義的工廠,比如這個通用之一:

public sealed class NamedDelegateFactory<T> : INamedFactory<T> 
{ 
    private readonly Func<string, T> factory; 

    public NamedDelegateFactory(Func<string, T> factory) 
    { 
     this.factory = factory; 
    } 

    public T GetByKey(string key) 
    { 
     return this.factory(key); 
    } 

    object INamedFactory.GetByKey(string key) 
    { 
     return this.factory(key); 
    } 
} 

可在容器中註冊如下:

var adapter = new LightCoreServiceLocatorAdapter(builder.Build()); 

Microsoft.Practices.ServiceLocation.ServiceLocator 
    .SetLocatorProvider(() => adapter); 

您可以使用註冊的所有命名實例:

var factory = new NamedDelegateFactory<IMyType>(key => 
{ 
    if (key == "Cool") return new MyType1(); 
    else return new MyType2(); 
}); 

var builder = new ContainerBuilder(); 
builder.Register<INamedFactory<IMyType>>(c => factory); 

接下來,LightCoreServiceLocatorAdapter可以如下創建INamedFactory<T>接口並使用NamedDelegateFactory<T>包裝在一個委託或實現一個自定義類型,實現INamedFactory<T>