2013-05-10 125 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(); 
} 

但是,这取决于你的情况,如果这个工程。

相关问题