2013-05-10 124 views
1

假設我有這樣的場景:如何註冊並使用相同接口的不同實現?

 
using System.Linq; 
using NUnit.Framework; 
public interface IChannel { 
    void Write(double value); 
} 

public class Channel: IChannel { 
    private readonly int channelNumber; 
    public Channel(int channelNumber) { 
     Requires.That(channelNumber >= 0, "channelNumber >= 0"); 
     this.channelNumber = channelNumber; 
    } 
    private int calls; 
    public void Write(double value) { 
     System.Console.WriteLine("{0} wrote on channel {1} [#{2}]", value.ToString(), channelNumber, ++calls); 
    } 
} 

public interface IService { 
    void Do(); 
} 

public class ServicePiGreek: IService { 
    private readonly IChannel channel; 
    public ServicePiGreek(IChannel channel) { 
     Requires.IsNotNull(channel, "channel"); 
     this.channel = channel; 
    } 
    public void Do() { 
     channel.Write(3.14); 
    } 
} 
public class ServiceEuler: IService { 
    private readonly IChannel channel; 
    public ServiceEuler(IChannel channel) { 
     Requires.IsNotNull(channel, "channel"); 
     this.channel = channel; 
    } 
    public void Do() { 
     channel.Write(2.71); 
    } 
} 

因此,我將創建兩個ServicePiGreek與通道0和1,並與通道0 ServiceEuler:

 
[TestFixture] 
public class Tests { 
    [Test]public void without_simpleinjector() { 
     var ch0 = new Channel(0); 
     var s0 = new ServicePiGreek(ch0); 
     var s1 = new ServicePiGreek(new Channel(1)); 
     var s2 = new ServiceEuler(ch0); 
     s0.Do(); 
     s1.Do(); 
     s2.Do(); 
    } 

我想到了這一點:

 
    [Test]public void with_simpleinjector() { 
     SimpleInjector.Container container = new SimpleInjector.Container(); 
     container.RegisterAll(new Channel(0), new Channel(1)); 
     container.RegisterAll(GetAllServices(container)); 

     foreach (var service in container.GetAllInstances()) { 
     service.Do(); 
     } 
    } 

    private System.Collections.Generic.IEnumerable GetAllServices(SimpleInjector.Container container) { 
     yield return new ServicePiGreek(container.GetAllInstances().ElementAt(1)); 
     yield return new ServicePiGreek(container.GetAllInstances().ElementAt(0)); 
     yield return new ServiceEuler(container.GetAllInstances().ElementAt(0)); 
    } 

有沒有人有更好的想法如何做到這一點?

回答

3

您的用例並不常見,因爲您在同一個列表中多次執行相同的實現(如瞬態),並需要使用不同的接口來實現。

我無法查看您的設計,但您現在如何註冊類型是有道理的。您註冊一個動態的IEnumerable,它在迭代時回調容器。很高興看到您使用Simple Injector的新功能之一,通過使用ElementAt這是O(1)操作獲取物品索引,因爲返回的集合實現了IList<T>

你可以做到以下幾點,以使代碼更易讀:

private IEnumerable<IService> GetAllServices(Container container) { 
    var channels = container.GetAllInstances<IChannel>(); 
    yield return new ServicePiGreek(channels.ElementAt(0)); 
    yield return new ServicePiGreek(channels.ElementAt(1)); 
    yield return new ServiceEuler(channels.ElementAt(0)); 

}

或者當IService實現可以是單身,你將能夠做到以下幾點:

var container = new SimpleInjector.Container(); 

var blueChannel = new Channel(0); 
var redChannel = new Channel(1); 

container.RegisterAll<IService>(
    new ServicePiGreek(blueChannel), 
    new ServicePiGreek(redChannel), 
    new ServiceEuler(blueChannel), 
); 

foreach (var service in container.GetAllInstances<IService>()) { 
    service.Do(); 
} 

您可以將它放在工廠後面,例如:

interface IChannelProvider 
{ 
    IChannel GetBlueChannel(); 
    IChannel GetRedChannel(); 
} 

但是,這取決於你的情況,如果這個工程。

相關問題