13

Я использую C# с Microsoft Unity framework. Я не совсем уверен, как решить эту проблему. Вероятно, это связано с моим недостатком понимания DI с Unity.Инъекция конструктора в C#/Unity?

Моя проблема может быть выражена с помощью следующего примера кода:

class Train(Person p) { ... } 

class Bus(Person p) { ... } 

class Person(string name) { ... } 

Person dad = new Person("joe"); 
Person son = new Person("timmy"); 

Когда я вызываю метод решимость на автобусе, как я могу быть уверен, что человек «сын» с именем «Тимми» впрыскивается и когда вы разрешаете Поезд, как я могу быть уверенным, что Папа человека с именем «joe» разрешен?

Я думаю, может быть, использовать именованные экземпляры? Но я в недоумении. Любая помощь будет оценена по достоинству.

В стороне, я бы предпочел не создавать интерфейс IPerson.

ответ

15

Одним из способов решения этого вопроса будет использование конструктора впрыска с именованной регистрацией.

// Register timmy this way 
Person son = new Person("Timmy"); 
container.RegisterInstance<Person>("son", son); 

// OR register timmy this way 
container.RegisterType<Person>("son", new InjectionConstructor("Timmy")); 

// Either way, register bus this way. 
container.RegisterType<Bus>(new InjectionConstructor(container.Resolve<Person>("son"))); 

// Repeat for Joe/Train 
+2

Каким образом можно сохранить их в конфигурационном файле, а не в hardcoding? –

32

Если вы не зарегистрируете соответственно «Джо» и «Тимми» в качестве имени зависимостей, вы не можете быть уверены в том, что «Тимми» вводится в Schoolbus. На самом деле, если вы попытаетесь зарегистрировать два экземпляра того же класса, что и неназванные зависимости, у вас будет неоднозначная настройка, и вы не сможете полностью разрешить Person.

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

Основная идея DI является создание механизма, который позволяет решить абстрактные типы (интерфейсы или абстрактные классы) в конкретные типы. В вашем примере нет абстрактных типов, поэтому на самом деле это не имеет особого смысла.

+0

Спасибо за ваш проницательный ответ. Хотя вы можете быть правы, DI и IoC являются для меня новыми концепциями, поэтому я все еще пытаюсь найти лучший дизайн. –

+1

Это справедливо - вы можете прочитать мою книгу, затем :) –

+2

JP, вы можете проверить его книгу. Я нашел это очень проницательным. –

14

Mark Seeman получил это право. И я сочувствую твоей неразберихе. Я сам прошел через это, когда научился использовать контейнеры для инъекций с автоматической загрузкой. Проблема в том, что существует много правильных и разумных способов проектирования и использования объектов. Тем не менее, только некоторые из этих подходов работают с контейнерами с инжекцией с автоматической зависимостью.

Моя личная история: Я изучил принципы построения объектов и инверсии управления задолго до того, как узнал, как использовать инверсию контрольных контейнеров, таких как контейнеры Unity или Castle Windsor. Я приобрел привычку писать код так:

public class Foo 
{ 
    IService _service; 
    int _accountNumber; 

    public Foo(IService service, int accountNumber) 
    { 
     _service = service; 
     _accountNumber = accountNumber; 
    } 
    public void SaveAccount() 
    { 
     _service.Save(_accountNumber); 

    } 
} 
public class Program 
{ 
    public static void Main() 
    { 
     Foo foo = new Foo(new Service(),1234); 
     foo.Save(); 
    } 
} 

В этом проекте, мой класс Foo отвечает за сохранение учетных записей в базе данных. Для этого требуется номер учетной записи, а также служба для выполнения грязной работы. Это несколько похоже на конкретные классы, которые вы указали выше, где каждый объект принимает некоторые уникальные значения в конструкторе. Это отлично работает при создании объектов с помощью собственного кода. Вы можете перейти в соответствующие значения в нужное время.

Однако, когда я узнал об автоматических контейнерах для инъекций, я обнаружил, что я больше не создавал Foo вручную. Контейнер будет создавать экземпляры конструктора для меня. Это было большим удобством для таких сервисов, как IService. Но это, очевидно, не так хорошо работает для целых чисел и строк и т. П. В этих случаях он будет предоставлять значение по умолчанию (например, нуль для целого числа).Вместо этого, я привык к переходящая в конкретном контексте ценностей, как номер счета, имя и т.д ... Так что мне пришлось корректировать свой стиль кодирования и дизайн быть похожим на это:

public class Foo 
{ 
    IService _service; 
    public Foo(IService service) 
    { 
     _service = service; 
    } 
    public void SaveAccount(int accountNumber) 
    { 
     _service.Save(accountNumber); 

    } 
} 
public class Program 
{ 
    public static void Main() 
    { 
     Foo foo = new Foo(new Service()); 
     foo.Save(1234); 
    } 
} 

Оказывается, что оба Классы Foo являются действительными проектами. Но второй можно использовать с автоматической инъекцией зависимостей, а первый - нет.

+4

Не следует ли использовать метод Main() больше: Foo foo = new Foo (new Service()); foo.Save (1234); ? – McBainUK

+0

На самом деле это должно быть foo.SaveAccount (1234) :) – sethidev

+0

Интересно не о инициализации 'int'. У меня просто был очень похожий случай (совершенно другой домен), где мне нужно было инициализировать таймаут - абстрагироваться от метода, – Thomas

Смежные вопросы