10

我需要这方面的帮助。我使用 Unity 作为我的容器,我想将两个相同类型的不同实例注入到我的构造函数中。

class Example
{
   Example(IQueue receiveQueue, IQueue sendQueue) {}
}

....并且 IQueue 在我的 MessageQueue 类中实现....

class MessageQueue : IQueue
{
    MessageQueue(string path) {}
}

如何将两个不同的 MessageQueue 实例注入到我的 Example 类中?使用不同路径创建的每个 MessageQueue 实例。

4

6 回答 6

7

有很多方法可以实现您想要的结果(正如多个答案所证明的那样)。这是使用命名注册(无属性)的另一种方式:

IUnityContainer container = new UnityContainer();

container.RegisterType<IQueue, MessageQueue>("ReceiveQueue", 
    new InjectionConstructor("receivePath"));

container.RegisterType<IQueue, MessageQueue>("SendQueue",
    new InjectionConstructor("sendPath"));

container.RegisterType<Example>(
    new InjectionConstructor(
        new ResolvedParameter<IQueue>("ReceiveQueue"),
        new ResolvedParameter<IQueue>("SendQueue")));

Example example = container.Resolve<Example>();

这种方法的缺点是,如果更改了 Example 构造函数,则还必须修改注册代码以匹配。此外,该错误将是运行时错误,而不是更可取的编译时错误。

您可以将上述内容与 InjectionFactory 结合起来手动调用构造函数以进行编译时检查:

IUnityContainer container = new UnityContainer();

container.RegisterType<IQueue, MessageQueue>("ReceiveQueue",
    new InjectionConstructor("receivePath"));

container.RegisterType<IQueue, MessageQueue>("SendQueue",
    new InjectionConstructor("sendPath"));

container.RegisterType<Example>(new InjectionFactory(c =>
    new Example(c.Resolve<IQueue>("ReceiveQueue"),
                c.Resolve<IQueue>("SendQueue"))));

Example example = container.Resolve<Example>();

如果您使用的是组合根,那么魔术字符串(“ReceiveQueue”和“SendQueue”)的使用将仅限于一个注册位置。

于 2013-08-27T17:02:44.673 回答
4

并非所有东西都必须由容器自动连接。您可以Example像这样注册课程:

container.Register<Example>(new InjectionFactory(c =>
{
    var receive = new MessageQueue("receivePath");
    var send = new MessageQueue("sendPath");
    return new Example(receive, send);
});
于 2013-08-27T07:59:59.340 回答
3

您可以使用名称注册两个实例:

myContainer.RegisterInstance<IQueue>("ReceiveQueue", myReceiveMessageQueue);
myContainer.RegisterInstance<IQueue>("SendQueue", mySendMessageQueue);

然后你应该能够按名称解析,但它需要使用Dependency属性:

class Example
{
    Example([Dependency("ReceiveQueue")] IQueue receiveQueue, 
            [Dependency("SendQueue")] IQueue sendQueue) {
   }
}

或注入统一容器,然后在构造函数中解析实例:

class Example
{
    Example(IUnityContainter container) 
    {
        _receiveQueue = container.Resolve<IQueue>("ReceiveQueue");
        _sendQueue = container.Resolve<IQueue>("SendQueue");
    }
}

于 2013-08-27T05:51:51.363 回答
2

好吧,不要

在这种情况下,您应该使用工厂模式。

class Example
{
   Example(IQueueFactory factory) 
   {
       _sendQueue = factory.Create("MySend");
       _receiveQueue = factory.Create("MyReceive");
   }
}

它使意图更加清晰,Example如果队列未找到或配置不正确,您可以在类内部处理。

于 2013-08-27T06:19:34.627 回答
2

5年后,但我也在寻找这个答案。我用我自己的代码完成了它,然后决定使用 OP 提供的(稍微改变的)类来创建工作代码。

这是一个完整的工作示例,您可以将其复制到LINQPad(程序员的游乐场)并运行。

使用语句/Unity 库

您需要添加对 Microsoft.Practices.Unity.dll 的引用您还需要添加以下 using 语句:

Microsoft.Practices.Unity

在 LinqPad 中,您按 F4 添加引用和 using 语句(命名空间导入)。

void Main()
{
    // Create your unity container (one-time creation)
    UnityContainer uc = new UnityContainer();

    // Create simple list to hold your target objects
    // (makes the sample easy to follow)
    List<MessageQueue> allMQs = new List<MessageQueue>();

    // I'm adding TransientLifetimeManager() in order to 
    // explicitly ask for new object creation each time
    // uc.Resolve<MessageQueue>() is called
    uc.RegisterType<IQueue, MessageQueue>(new TransientLifetimeManager());
// ### override the parameters by matching the parameter name (inPath)
    var item = uc.Resolve<MessageQueue>(new ParameterOverride("inPath", "extra.txt").OnType<MessageQueue>());
    allMQs.Add(item);
    item = uc.Resolve<MessageQueue>(new ParameterOverride("inPath", "super.txt").OnType<MessageQueue>());
    allMQs.Add(item);

    foreach (MessageQueue mq in allMQs){
        Console.WriteLine($"mq.Path : {mq.Path}");
    }

    Console.WriteLine("######################\n");

    uc.RegisterType<Example>(new InjectionConstructor((allMQs[0] as IQueue),(allMQs[1] as IQueue)));

    // #### Create a new Example from the UnityContainer
    var example1 = uc.Resolve<Example>();
    // ##### Notice that the Example object uses the default values of super.txt & extra.txt

    Console.WriteLine("#### example1 obj. uses default values ###########");
    Console.WriteLine($"example1.receiver.Path : {example1.receiver.Path}");
    Console.WriteLine($"example1.sender.Path : {example1.sender.Path}");

    // ##################################################
    // Override the parameters that he Example class uses.
 // ### override the parameters by matching the parameter 
 // names (receiveQueue, sendQueue) found in the target
// class constructor (Example class)
    var example2 = uc.Resolve<Example>( 
        new ParameterOverrides {
             {"receiveQueue", new MessageQueue("newReceiveFile")},
             { "sendQueue", new MessageQueue("newSendFile")}
        }.OnType<Example>());

    Console.WriteLine("######################\n");

    Console.WriteLine("#### example1 obj. uses ParameterOverride values ###########");
    Console.WriteLine($"example2.sender.Path : {example2.sender.Path}");
    Console.WriteLine($"example2.receiver.Path : {example2.receiver.Path}");
}

class Example
{
   public MessageQueue receiver {get;set;}
   public MessageQueue sender {get;set;}

   public Example(IQueue receiveQueue, IQueue sendQueue) {
    this.receiver = receiveQueue as MessageQueue;
    this.sender = sendQueue as MessageQueue;

   }
}

public class MessageQueue : IQueue
{
    public string Path {get;set;}
    public MessageQueue(string inPath) {
        Path = inPath;}
}

interface IQueue{

}

考试输出

如果您运行上面的脚本,您将看到如下示例输出:

mq.Path : extra.txt
mq.Path : super.txt
######################

#### example1 obj. uses default values ###########
example1.receiver.Path : extra.txt
example1.sender.Path : super.txt
######################

#### example1 obj. uses ParameterOverride values ###########
example2.sender.Path : newSendFile
example2.receiver.Path : newReceiveFile
于 2019-05-20T17:33:32.470 回答
1

我认为这已经在 Stackoverflow 上被问过。您需要使用 ParameterOverride:

ParameterOverride 使您能够传入构造函数参数的值,以覆盖传递给给定命名构造函数的参数。只有参数值被覆盖,而不是构造函数。

链接到 MSDN 文章

链接到 Stackoverflow 文章

var exampleInstance = new Example();

var queue1 = unityContainer.Resolve<IQueue>(new ParameterOverrides<MessageQueue> { { "path", "yourPath" }});

var queue2 = unityContainer.Resolve<IQueue>(new ParameterOverrides<MessageQueue> { { "path", "yourPath2Queue2" }});

exampleInstance.Example(queue1,queue2);
于 2013-08-27T05:53:43.440 回答