Pregunta

Estoy usando C# con el marco Unity de Microsoft. No estoy muy seguro de cómo resolver este problema. Probablemente tenga algo que ver con mi falta de comprensión con la unidad.

Mi problema se puede resumir utilizando el siguiente código de ejemplo:

class Train(Person p) { ... }

class Bus(Person p) { ... }

class Person(string name) { ... }

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

Cuando llamo al método de resolución en el autobús, ¿cómo puedo estar seguro de que la persona 'hijo' con el nombre 'Timmy' se inyecta y al resolver el tren, ¿cómo puedo estar seguro de que esa persona 'papá' con el nombre 'Joe' se resuelve?

¿Estoy pensando que tal vez use instancias nombradas? Pero estoy perdido. Cualquier ayuda sería apreciada.

Como aparte, prefiero no crear una interfaz iperson.

¿Fue útil?

Solución

Una forma de resolver esto sería usar un constructor de inyección con un registro con nombre.

// 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

Otros consejos

A menos que se registre respectivamente "Joe" y "Timmy" como las dependencias nombradas, no puede estar seguro de que "Timmy" se inyecta en la escuela. De hecho, si intenta registrar dos instancias de la misma clase que las dependencias no identificadas, tendrá una configuración ambigua y no podrá resolver Person en absoluto.

En general, si tiene que registrar muchas instancias nombradas, probablemente esté haciendo DI de la manera incorrecta. La idea principal de DI es resolver Servicios de dominio más que Objetos de dominio.

La idea principal de DI es proporcionar un mecanismo que le permita resolver tipos abstractos (interfaces o clases abstractas) en tipos de concreto. Su ejemplo no tiene tipos abstractos, por lo que realmente no tiene mucho sentido.

Mark Seeman lo hizo bien. Y simpatizo con tu confusión. Lo revisé yo mismo cuando aprendí a usar contenedores de inyección de dependencia automática. El problema es que hay muchas formas válidas y razonables de diseñar y usar objetos. Sin embargo, solo algunos de esos enfoques funcionan con contenedores de inyección de dependencia automática.

Mi historia personal: aprendí principios OO de construcción de objetos e inversión de control mucho antes de aprender a usar la inversión de contenedores de control como los contenedores de la unidad o el Castillo Windsor. Adquirí el hábito de escribir código como este:

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

En este diseño, mi clase FOO es responsable de guardar cuentas en la base de datos. Necesita un número de cuenta para hacer eso y un servicio para hacer el trabajo sucio. Esto es algo similar a las clases concretadas que proporcionó anteriormente, donde cada objeto toma algunos valores únicos en el constructor. Esto funciona bien cuando instancia los objetos con su propio código. Puede pasar por los valores apropiados en el momento adecuado.

Sin embargo, cuando aprendí sobre contenedores de inyección de dependencia automática, descubrí que ya no estaba instanciando Foo a mano. El contenedor instanciaría los argumentos del constructor para mí. Esta fue una gran comodidad para los servicios como IService. Pero obviamente no funciona tan bien para enteros y cuerdas y similares. En esos casos, proporcionaría un valor predeterminado (como cero para un entero). En cambio, me había acostumbrado a pasar en valores específicos del contexto como el número de cuenta, el nombre, etc., así que tuve que ajustar mi estilo de codificación y diseño para ser así:

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

Parece que ambas clases de FOO son diseños válidos. Pero el segundo es utilizable con la inyección automática de dependencia, y el primero no lo es.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top