2009-04-13 38 views
29

¿Alguien puede explicar inyección de dependenciaconun ejemplo básico de .NET y proporcionar algunos enlaces a recursos de .NET para ampliar el tema?Dependency Injection en .NET con ejemplos?

Esto no es un duplicado de What is dependency injection? porque estoy preguntando sobre ejemplos y recursos específicos de .NET.

+1

Martin Fowler tiene la descripción cubierto: http: // Martin Fowler. com/articles/injection.html En cuanto a los recursos de .NET, eche un vistazo a: - [Castle Windsor] (http://www.castleproject.org/container/index.html) - [Spring.NET] (http: //www.springframework.net/) - [Autofac] (http://code.google.com/p/autofac/) - [Ninject] (http://ninject.org/) - [Unity] (http: //www.codeplex.com/unity) - [Mapa de estructura] (http://structuremap.sourceforge.net/) – Codebrain

+0

Eche un vistazo a los siguientes artículos que pueden brindar ayuda sobre esto: * [Windsor IoC Container en un Lunch Break] (http://jeremyjarrell.com/archive/2007/07/12/44.aspx) * [Artículo de MSDN sobre Inversion of Control and Dependency Injection] (http://msdn.microsoft.com/en-us/library/aa973811.aspx) Enlace general sobre el contenedor: * [Castle Project] (http: // www) .castleproject.org/container/index.html) Un par de enlaces de SO que pueden ayudar a otras cosas sobre el tema: * [Preguntas de Castle Windsor] (http://stackoverflow.com/questions/tagged/castle-windsor) * [ Preguntas sobre la IoC] (http://stackoverflow.com/questions/t –

Respuesta

32

Aquí hay un ejemplo común. Debes iniciar sesión en tu aplicación. Pero, en el momento del diseño, no está seguro de si el cliente desea iniciar sesión en una base de datos, archivos o el registro de eventos.

Por lo tanto, desea utilizar DI para diferir esa elección a una que pueda ser configurada por el cliente.

Esto es algo de pseudocódigo (más o menos basada en la unidad):

Se crea un interfaz de registro:

public interface ILog 
{ 
    void Log(string text); 
} 

a continuación, utilizar esta interfaz en sus clases

public class SomeClass 
{ 
    [Dependency] 
    public ILog Log {get;set;} 
} 

inyectar esas dependencias a las tiempo de ejecución

public class SomeClassFactory 
{ 
    public SomeClass Create() 
    { 
    var result = new SomeClass(); 
    DependencyInjector.Inject(result); 
    return result; 
    } 
} 

y la instancia se configura en app.config:

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <configSections> 
    <section name ="unity" 
      type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, 
       Microsoft.Practices.Unity.Configuration"/> 
    </configSections> 
    <unity> 
    <typeAliases> 
     <typeAlias alias="singleton" 
       type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,Microsoft.Practices.Unity" /> 
    </typeAliases> 
    <containers> 
     <container> 
     <types> 
      <type type="MyAssembly.ILog,MyAssembly" 
       mapTo="MyImplementations.SqlLog, MyImplementations"> 
      <lifetime type="singleton"/> 
      </type> 
     </types> 
     </container> 
    </containers> 
    </unity> 
</configuration> 

Ahora bien, si desea cambiar el tipo de registrador, que acaba de entrar en la configuración y especifique otro tipo.

+48

Ese no es el punto. – Will

+2

no es así :) - gracias por el útil ejemplo – JohnIdol

+1

¿Por qué no podemos usar algún atributo personalizado y definir 1 = base de datos, 2 = archivo y etc.? ¿Para qué necesitamos la Unidad? –

0

Básicamente se pasan todos los objetos necesarios en el constructor. Alternativamente, puede resolverlos en tiempo de ejecución usando una resolución de interfaz (aunque esto es menos seguro). Puede encontrar excelentes ejemplos en el sitio web de Ninject para el primer acercamiento, y buenos ejemplos en el sitio web Unity para el segundo enfoque. Esto evita la necesidad de singletons y le permite colocar fácilmente un objeto de reemplazo que se ajuste a la interfaz deseada

1

Tengo Dependency Injection con un ejemplo realmente simple como este.

Consulte la clase a continuación, obtendrá la idea completa. Como ve, a menos que suministre el archivo, usará el archivo predeterminado de configuración, pero puede establecer un archivo de configuración y luego la clase lo usará.

Public Class ProcessFile 

Private _SettingsFile As String = "settings.bin" 

Public Sub New() 
End Sub 

Public Sub New(settings As String) 
_SettingsFile= settings 
End Sub 

Public Function ReadFile() As String 
'Do stuff based on the settings stored in the _SettingsFile 
End Function 

End Class 

Obviamente, este es el caso más básico. En el mundo real, puede hacer lo mismo con los tipos de clase, como la Capa de base de datos y puede cambiar la base de datos subyacente haciendo inyección de dependencia y su código funcionará con cualquier base de datos tan pronto como pueda proporcionar la clase válida. (una clase que implementa la interfaz que está utilizando).

Después de obtener lo básico, puede hacerlo en un ámbito más amplio y totalmente independiente de la aplicación utilizando marcos DI como unity.

30

Ninject debe tener una de las muestras más fresco por ahí: (juntado las piezas de la muestra)

interface IWeapon { 
    void Hit(string target); 
} 
class Sword : IWeapon { 
    public void Hit(string target) { 
    Console.WriteLine("Chopped {0} clean in half", target); 
    } 
} 
class Shuriken : IWeapon { 
    public void Hit(string target) { 
    Console.WriteLine("Shuriken tossed on {0}", target); 
    } 
} 
class Samurai { 
    private IWeapon _weapon; 

    [Inject] 
    public Samurai(IWeapon weapon) { 
    _weapon = weapon; 
    } 

    public void Attack(string target) { 
    _weapon.Hit(target); 
    } 
} 

class WeaponsModule: NinjectModule { 
    private readonly bool _useMeleeWeapons; 

    public WeaponsModule(bool useMeleeWeapons) { 
    _useMeleeWeapons = useMeleeWeapons; 
    } 

    public void Load() { 
    if (useMeleeWeapons) 
     Bind<IWeapon>().To<Sword>(); 
    else 
     Bind<IWeapon>().To<Shuriken>(); 
    } 
} 

class Program { 
    public static void Main() { 
    bool useMeleeWeapons = false; 
    IKernel kernel = new StandardKernel(new WeaponsModule(useMeleeWeapons)); 
    Samurai warrior = kernel.Get<Samurai>(); 
    warrior.Attack("the evildoers"); 
    } 
} 

Esto, para mí, lee con gran fluidez, antes de que arranque el dojo puede decidir cómo armar su Samurais.

+2

Lo siento, no lo entiendo. ¿Por qué es esto mejor que escribir código que haga "nuevo Samurai (useMeleeWeapons);"? ¿No sería este el más fluido? – Nabheet

+1

Supongamos que tienes un ejército de 10,000 samurais ... y escribes esa línea 10,000 veces ... y luego quieres cambiarlo, pero desafortunadamente no puedes usar el buscador de encontrar/reemplazar ... en el párrafo anterior ejemplo, todo lo que necesitas hacer es cambiar el 'WeaponsModule' :) – Noctis

+2

¿Cuándo y cómo se llama' Load() 'en' WeaponsModule'? – GFoley83

0

Instale a continuación los paquetes Nuget en el nombre del proyecto mvc4 principal SampleDependency. Unity.mvc4, unity.webapi y MicrosoftAsp.Net API Web de host Web 2.2

En proyecto web

public static class Bootstrapper 
{ 
    public static IUnityContainer Initialise() 
    { 
     var container = BuildUnityContainer(); 

     DependencyResolver.SetResolver(new UnityDependencyResolver(container)); 
     GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container); 

     return container; 
    } 

    private static IUnityContainer BuildUnityContainer() 
    { 
     var container = new UnityContainer(); 

     // register all your components with the container here 
     // it is NOT necessary to register your controllers 

     // e.g. container.RegisterType<ITestService, TestService>(); 
     container.RegisterType<IUserDetailLogic, UserDetailLogic>(); 
     container.RegisterType<IUserData, UserData>(); 

     RegisterTypes(container); 

     return container; 
    } 
    public static void RegisterTypes(IUnityContainer container) 
    { 

    } 
} 
0

Crear proyecto capa de base de datos (biblioteca de clases) y añadir a continuación código en él.

public class UserData : IUserData 
{ 
    public string getUserDetails() 
    { 
     return "Asif"; 
    } 
} 

public interface IUserData 
{ 
    string getUserDetails(); 
} 
0

Agregue el proyecto de lógica de negocio de la biblioteca de clases de tipo y añada a continuación el código en él. public class UserDetailLogic: IUserDetailLogic { private IUserData _userData = null;

public UserDetailLogic(IUserData userData) 
    { 
     _userData = userData; 
    } 
    public string getUserDetails() 
    { 
     return _userData.getUserDetails(); 
    } 
} 

public interface IUserDetailLogic 
{ 
    string getUserDetails(); 
} 

En su proyecto principal, agregue el código siguiente en el controlador del hogar.

clase pública HomeController: Controller { private readonly IUserDetailLogic _userDetailLogic;

public HomeController(IUserDetailLogic userDetailLogic) 
    { 
     _userDetailLogic = userDetailLogic; 
    } 

    public ActionResult Index() 
    { 
     ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; 
     string str = _userDetailLogic.getUserDetails(); 
     return View(); 
    } 

    public ActionResult About() 
    { 
     ViewBag.Message = "Your app description page."; 

     return View(); 
    } 

    public ActionResult Contact() 
    { 
     ViewBag.Message = "Your contact page."; 

     return View(); 
    } 
} 
+0

Buena publicación, pero no está claro (al menos para mí) cuando noté que userData usa la interfaz IUserData (en lugar de IUserDetailLogic ¿quizás?). También HomeController espera IUserDetailLogic userDetailLogic que, en mi experiencia/conocimiento, no sé de dónde vendrá. – Ichirichi

3

Creo que es importante que primero aprenda DI sin IoC Containers. Por lo tanto, he escrito un ejemplo que lentamente se convierte en un Contenedor de IoC. Es un ejemplo real de mi trabajo, pero todavía lo suficientemente básico como para que los principiantes capten la esencia de DI. Puede encontrarlo aquí: https://dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/

Está en C# .NET y luego usa Unity.

Update después de comentario:

parte relevante el artículo

"Tenga en cuenta las siguientes modificaciones en el diseño original:

quick graph of situation

Fuimos por la“inyección de constructor "Patrón para implementar DI y los pasos de refactorización fueron:

  1. Resuma la interfaz de CardPresenceChecker mediante la creación de la interfaz ICardPresenceChecker;
  2. Haga explícito que este CardPresenceChecker solo funciona para la biblioteca de la Empresa X, cambiando su nombre a XCardPresenceChecker;
  3. Haga que XCardPresenceChecker implemente la interfaz ICardPresenceChecker;
  4. Resuma la propiedad de LogInService para ser del tipo ICardPresenceChecker en lugar de 'saber' exactamente qué implementación de se lleva a bordo;
  5. Y por último pero no menos importante, demanda de los usuarios (otros desarrolladores) de LogInService que proporcionen cualquier clase que al menos implemente ICardPresenceChecker para que LogInService pueda hacer su trabajo.

el constructor de LoginService parece:

this.myCardPresenceChecker = cardPresenceChecker; 
this.myCardPresenceChecker.CardIn += MyCardPresenceChecker_CardIn; 
this.myCardPresenceChecker.CardOut += MyCardPresenceChecker_CardOut; 
this.myCardPresenceChecker.Init(); 

también lo hacen en el que proporcionar LoginService con una implementación de ICardPresenceChecker? Por lo general, desea este 'mapeo' (en este ejemplo, 'asignaremos' ICardPresenceChecker a XCardPresenceChecker) en un lugar central al inicio de una aplicación, conocida conceptualmente como la '' Raíz de composición ''. Para una vieja aplicación de consola normal que podría ser el vacío principal en la clase de programa. Así que para este ejemplo, este fragmento de código se aplica en el lugar aformentioned:

LoginService LoginService = new LoginService (nueva XCardPresenceChecker());"

+1

Si bien este enlace puede responder la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace de referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. - [De la crítica] (/ review/low-quality-posts/11421227) –

+0

@Nahuel lanni: Aunque aprecio su comentario y trataré de cumplirlo, mi punto es que es importante leer el artículo completo y no solo intente aprender de un fragmento de código aleatorio. Pero ... Ver respuesta revisada. Espero que esto ayude. –

+0

IoC? ¿Que es eso? :-( – Ichirichi

Cuestiones relacionadas