Constructor Injection w C# / Unity?

Używam C# z Unity framework Microsoftu. Nie jestem pewien, jak rozwiązać ten problem. To pewnie ma coś wspólnego z moim brakiem zrozumienia DI z Unity.

Mój problem można podsumować używając poniższego przykładowego kodu:

class Train(Person p) { ... }

class Bus(Person p) { ... }

class Person(string name) { ... }

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

Kiedy wywołuję metodę resolve w autobusie, jak Mogę być pewien, że osoba " syn "o imieniu" timmy "została wstrzyknięta, a kiedy rozwiązuję pociąg, jak Mogę być pewien, że osoba "tata" o imieniu " joe " została rozwiązana?

I ' m myślisz, że możesz użyć nazwanych instancji? Ale jestem w rozsypce. Każda pomoc będzie mile widziana.

Na marginesie, wolałbym nie tworzyć interfejsu IPerson.

Author: JP Richardson, 2010-01-06

3 answers

Jednym ze sposobów rozwiązania tego problemu byłoby użycie konstruktora wtrysku o nazwie rejestracji.

// 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
 16
Author: Daniel Auger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-06 19:46:05

Jeśli nie zarejestrujesz odpowiednio " joe " i " timmy "jako nazwane zależności, nie możesz być pewien, że" timmy " jest wstrzykiwany do Schoolbus. W rzeczywistości, jeśli spróbujesz zarejestrować dwie instancje tej samej klasy jako nienazwane zależności, będziesz miał niejednoznaczną konfigurację i nie będziesz w stanie rozwiązać Person w ogóle.

Ogólnie rzecz biorąc, jeśli musisz zarejestrować wiele nazwanych instancji, prawdopodobnie będziesz postępować o DI w niewłaściwy sposób. Głównym założeniem DI jest rozwiązywanie usług domenowych więcej niż obiektów domeny .

Podstawową ideą DI jest dostarczenie mechanizmu, który pozwala na rozdzielenie typów abstrakcyjnych (interfejsów lub klas abstrakcyjnych) na konkretne typy. Twój przykład nie ma abstrakcyjnych typów, więc nie ma zbyt wiele sensu.

 34
Author: Mark Seemann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-06 19:21:09

Mark Seeman dobrze to zrozumiał. I współczuję Twojej dezorientacji. Sam przez to przeszedłem, kiedy nauczyłem się używać automatycznych kontenerów do wstrzykiwania zależności. Problem polega na tym, że istnieje wiele ważnych i rozsądnych sposobów projektowania i używania obiektów. Jednak tylko niektóre z tych podejść działają z automatycznymi kontenerami zależności injectorion.

Moja osobista historia: nauczyłem się zasad budowy obiektów i inwersji Sterowania na długo przed tym, jak używać inwersji sterowania kontenery takie jak Unity lub Castle Windsor containers. Nabrałem nawyku pisania kodu w ten sposób:

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();
     }
}

W tym projekcie moja klasa Foo jest odpowiedzialna za zapisywanie kont do bazy danych. Do tego potrzebny jest numer konta i usługa do wykonania brudnej roboty. Jest to nieco podobne do klas betonowych, które podałeś powyżej, gdzie każdy obiekt przyjmuje pewne unikalne wartości w konstruktorze. Działa to dobrze, gdy tworzysz instancje obiektów za pomocą własnego kodu. Można przejść w odpowiednie wartości we właściwym czasie.

Jednak, kiedy dowiedziałem się o automatycznych kontenerach wtrysku zależności, odkryłem, że nie tworzyłem już ręcznie Foo. Kontener utworzyłby dla mnie instancję argumentów konstruktora. Było to duże udogodnienie dla usług takich jak IService. Ale to oczywiście nie działa tak dobrze dla liczb całkowitych, ciągów itd. W takich przypadkach będzie to wartość domyślna (np. zero dla liczby całkowitej). Zamiast tego przywykłem do przekazywanie wartości kontekstowych, takich jak numer konta, nazwa itp... Więc musiałem dostosować mój styl kodowania i projektowania, aby był taki:

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);
     }
}

Wygląda na to, że obie klasy Foo są poprawnymi projektami. Ale drugi jest użyteczny z automatycznym wtryskiem zależności, a pierwszy nie.

 14
Author: David Allen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-20 06:52:27