Инъекция зависимости - правильное место для инъекции - PullRequest
2 голосов
/ 25 июля 2011

Глядя на этот ответ по SO , я немного смущен следующим "принципом":

Применим принцип Голливуда

Голливудский принцип в терминах DI гласит: Не вызывайте DI-контейнер, он позвонит вам.

Никогда не запрашивайте зависимость напрямую, вызывая контейнериз вашего кода.Запрашивайте это неявно, используя Constructor Injection.

Но что, если у меня есть класс репозитория в моем DAL, и я хочу предоставить этот экземпляр объекту, который создается, когда TCP /IP-клиент подключается?В каком месте я должен сделать инъекцию?

Прямо сейчас у меня есть что-то вроде:

// gets created when a new TCP/IP client is connected
class Worker
{
    private readonly IClient client;
    public Worker(IClient client)
    {
        // get the repository
        var repo = IoC.GetInstance<IClientMessagesRepo>();

        // create an object which will parse messages
        var parser = new MessageParser(client);

        // create an object which will save them to repo
        var logger = new MessageLogger(parser, repo);
    }
}

Я, очевидно, не могу создать этот экземпляр при запуске моего приложения.Так, где я могу сделать репо?

Большое спасибо!

Ответы [ 4 ]

1 голос
/ 25 июля 2011

Вы должны стремиться звонить IoC.GetInstance() только один раз.

Поскольку вы не можете создать Worker при запуске, вы должны вместо этого создать WorkerFactory и сделать так, чтобы контейнер DI вставлял в него зависимость:

public class WorkerFactory
{
    private readonly IClientMessagesRepo clientMessagesRepo;
    public WorkerFactory(IClientMessagesRepo clientMessagesRepo)
    {
        this.clientMessagesRepo = clientMessagesRepo;
    }

    public Worker Create(IClient client)
    {
        return new Worker(client, clientMessagesRepo);
    }
}
0 голосов
/ 25 июля 2011

Имейте в своих аргументах IClientMessagesRepo, и пусть IoC заполнит это для вас:

public Worker(IClient client, IClientMessagesRepo repo)    
{
    [...]
}

Очевидно, ваш конструктор должен сделать немного больше, чем просто создать пару локальных переменных, но вы получитеидея.

0 голосов
/ 25 июля 2011

Как я понимаю, у вас есть хранилище в вашем контейнере IOC, но нет IClient. Предполагая, что вы имеете доступ к контейнеру IOC во время создания своего рабочего класса, и предполагая, что вы используете StructureMap, вы можете написать:

IClient concreteClient = ...;
worker = container.Using<IClient>(concreteClient).GetInstance<Worker>();

Таким образом, вы указываете StructureMap использовать конкретный экземпляр IClient, но получаете другие зависимости из хранилища.

примечание: Прошло некоторое время с тех пор, как я последний раз использовал StructureMap, поэтому, возможно, код не на 100% правильный, но концепция существует, вы можете предоставить конкретную зависимость при создании компонента.

0 голосов
/ 25 июля 2011

Переместить IClientMessagesRepo в аргументы вашего конструктора:

public Worker(IClient client,IClientMessagesRepo clientMessagesRepo)

Теперь, конечно, это только немного сдвигает проблему к точке, где создается работник. Конечно, в какой-то момент необходимы вызовы в контейнер IoC. Но в этих случаях я бы предпочел передать контейнер в параметре, а не обращаться к нему из статического свойства. Или использовать какую-то фабрику.

...