在仍使用依赖注入的同时创建新实例

时间:2011-08-02 16:21:38

标签: c# dependency-injection unity-container ioc-container

环境的简要描述:

我有一个代表聊天室并且依赖于记录器的类。它与具有横切关注点的系统级记录器不同,而是与特定聊天室相关联的记录器。它将该聊天室中的所有活动记录到其唯一的日志文件中。创建聊天室时,我想打开日志文件,当它被销毁时,我想关闭日志文件。

问题

这是我正在使用的相关代码。

public interface IChatroomLogger
{
    void Log(ServerPacket packet);
    void Open();
    void Close();
}

public class ChatroomLogger : IChatroomLogger
{
    // chatroom name will be used as a file name
    public ChatroomLogger(string chatroomName) { ... }
    public void Log(ServerPacket packet) { ... }
}

public class Chatroom
{
    public Chatroom(string name, IChatroomLogger logger)
    {
        this.name = name;
        this.logger = logger;
        this.logger.Open();
    }

    public IChatromLogger Logger { get { return this.logger; } }
}

public interface IChatManager
{
    Chatroom Get(chatroomName);
}

它在这样的应用程序中使用:

var room = ChatManager.Get(chatroomName);
romm.DoStuff();
room.Logger.LogPacket(receivedPacket);

ChatManager是一个类,它包含对所有聊天室的引用,并负责创建和删除它们。我还没有写它,但这是我编写的界面。

问题

如何让ChatManager创建Chatroom的新实例并仍然使用依赖注入?

我正在使用Unity来完成我所有其他的DI工作。到目前为止它的效果很好。但我不知道如何解决这个难题。

当我ChatManager的具体实现创建新的聊天室时,它必须传入IChatroomLogger。它不知道如何构建......但Unity确实如此。但是我必须将IUnityContainer传入ChatManager

public class ChatManager : IChatManager
{
    public ChatManager(IUnityContainer container)
    {
        this.container = container;
    }

    public Chat Get(string chatroomName)
    {
        // get logger from Unity somehow. Not sure how I'd 
        // pass chatroomName to the concrete instance
        var logger = ...
        return new Chatroom(chatroomName, logger);
    }
}

由于某种原因,这似乎是错误的。如果没有域名知道我正在使用什么DI容器,这似乎更清晰。

如果我的应用程序在运行过程中没有求助于某种服务定位器设计,我怎么能得到类Chatroom的新实例?我是否在思考它?绕过Unity是不是一件大事?欢迎任何想法!

2 个答案:

答案 0 :(得分:4)

你是对的。像这样使用IUnityContainer不再使用依赖注入。相反,它使用“服务定位器”模式。我通常在这种情况下做的是创建一个IFactory<T>接口,如下所示:

public IFactory<T>
{
    T Get();
}

然后使用 知道的类实现接口并使用IUnityContainer。设置绑定,以便IFactory<>请求将创建此工厂类的实例。这样,您可以将IFactory<Logger>接口注入ChatManager,并在需要记录器实例时随时调用.Get()

答案 1 :(得分:1)

一般来说,我也认为你应该避免绕过容器。

  • 使用Create(字符串房间名称)方法
  • 为您的设计添加IChatroomProvider
  • 在ChatroomProvider中,使用容器创建命名实例(容器将为您管理每个命名实例的生命周期,因此您无需管理字典)。
  • 使用容器注册ChatroomProvider
  • 让ChatManager依赖IChatroomProvider
  • 当ChatManager需要聊天室时,它可以询问其IChatroomProvider
  • 使用容器创建ChatManager实例
  • 创建聊天室时将创建记录器实例