2009-04-13 28 views
29

Qualcuno può spiegare iniezione di dipendenzaconun esempio .NET base e fornire una serie di link a .NET risorse per estendere su questo argomento?Iniezione delle dipendenze in .NET con esempi?

Questo non è un duplicato di What is dependency injection? perché sto chiedendo specifici esempi e risorse .NET.

+1

Martin Fowler ha la descrizione coperto: http: // Martin Fowler. it/articles/injection.html Per quanto riguarda le risorse .NET, dare un'occhiata 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) - [Structure Map] (http://structuremap.sourceforge.net/) – Codebrain

+0

Dai uno sguardo ai seguenti articoli che possono fornire qualche aiuto su questo: * [Windsor IoC Container on a Pausa pranzo] (http://jeremyjarrell.com/archive/2007/07/12/44.aspx) * [Articolo MSDN su Inversion of Control and Dependency Injection] (http://msdn.microsoft.com/en-us/library/aa973811.aspx) Link generale sul contenitore: * [Progetto castello] (http: // www .castleproject.org/container/index.html) Un paio di link SO che possono aiutare ulteriori cose sull'argomento: * [Domande Castle Windsor] (http://stackoverflow.com/questions/tagged/castle-windsor) * [ Domande IoC] (http://stackoverflow.com/questions/t –

risposta

32

Ecco un esempio comune. Devi accedere alla tua domanda. Tuttavia, in fase di progettazione, non si è sicuri che il client desideri accedere a un database, a file o al registro eventi.

Quindi, si desidera utilizzare DI per posticipare tale scelta a una che può essere configurata dal client.

Si tratta di alcuni pseudocodice (o meno sulla base di unità):

Si crea un interfaccia di registrazione:

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

quindi utilizzare questa interfaccia nelle classi

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

iniettare quelle dipendenze a runtime

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

e l'istanza è configurato in 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> 

Ora, se si desidera modificare il tipo di registratore, basta andare nella configurazione e specificare un altro tipo.

+48

Non è questo il punto. – Will

+2

non è proprio così :) - grazie per l'utile esempio – JohnIdol

+1

Perché non possiamo usare solo un attributo personalizzato e definire 1 = database, 2 = file ed ecc.? Per cosa abbiamo bisogno dell'Unità? –

0

In sostanza, si passa tutti gli oggetti necessari nel costruttore. In alternativa, è possibile risolverli in fase di esecuzione utilizzando un resolver di interfaccia (anche se questo è meno tipicamente sicuro). È possibile trovare esempi eccellenti sul sito Web di Ninject per il primo approccio e buoni esempi sul sito Web Unity per il secondo approccio. Ciò evita la necessità di singleton e consente di inserire facilmente un oggetto sostitutivo conforme all'interfaccia desiderata

1

Ho Iniezione di Dipendenza con un esempio molto semplice come questo.

Vedi la lezione qui sotto, riceverai l'intera idea. Come vedi, a meno che tu non fornisca il file, verrà utilizzato il file delle impostazioni predefinito, ma puoi impostare un file di impostazioni e la classe lo utilizzerà.

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 

Ovviamente questo è il caso più semplice. Nel mondo reale puoi fare la stessa cosa con i tipi di classe, come ad esempio il Database Layer e puoi cambiare la DLL del database sottostante facendo un'iniezione di dipendenza e il codice funzionerà con qualsiasi database non appena puoi fornire la classe valida (una classe che implementa l'interfaccia che stai utilizzando).

Dopo aver ottenuto l'essenziale, è possibile farlo su un ambito più ampio e totalmente indipendente dall'applicazione utilizzando quadri DI come unità.

30

Ninject deve avere uno dei campioni più cool là fuori: (ricostruito dal campione)

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

Questo, per me, si legge molto scorrevole, prima di iniziare il vostro dojo si può decidere come armare il tuo samurai.

+2

Mi dispiace, non capisco. Perché è meglio di me scrivere codice che fa "nuovo Samurai (useMeleeWeapons);"? Non sarebbe questo il più fluente? – Nabheet

+1

Supponiamo che tu abbia un esercito di 10.000 samurai ... e tu scrivi quella linea 10.000 volte ... e poi vuoi cambiarlo, ma ahimè, non puoi usare il Trova/Sostituisci dell'editor ... nel suddetto esempio, tutto quello che devi fare è cambiare il 'WeaponsModule' :) – Noctis

+2

Quando e come viene chiamato' Load() 'in' WeaponsModule'? – GFoley83

0

Installare sotto i pacchetti Nuget nel nome progetto principale mvc4 SampleDependency. Unity.mvc4, unity.webapi e MicrosoftAsp.Net Web API ospite 2.2 Web

in Project 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

Crea progetto strato di DB (libreria di classi) e aggiungere sotto codice in esso.

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

public interface IUserData 
{ 
    string getUserDetails(); 
} 
0

Aggiungere il progetto di logica di bussiness della libreria di classi del tipo e aggiungere sotto il codice in esso. 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(); 
} 

Nel tuo progetto principale aggiungi sotto il codice nel controller di casa.

classe pubblica 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

Buon post ma diventa un po 'oscuro (almeno per me) quando ho notato userData utilizza l'interfaccia IUserData (piuttosto che IUserDetailLogic forse?). Anche HomeController si aspetta che IUserDetailLogic userDetailLogic che, nella mia esperienza/conoscenza, non so da dove verrà. – Ichirichi

3

Penso che sia importante imparare prima DI senza Contenitori IoC. Quindi per questo ho scritto un esempio che cresce lentamente fino a un contenitore IoC. È un esempio reale del mio lavoro, ma ancora abbastanza semplice per i principianti per afferrare l'essenza di DI. Puoi trovarlo qui: https://dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/

È in C# .NET e in seguito utilizza Unity.

Aggiornamento dopo il commento:

sezione pertinente dell'articolo

"Osservare le seguenti modifiche al progetto originale:

quick graph of situation

Ci siamo andati per il“iniezione Constructor "Schema per implementare DI e le fasi di refactoring erano:

  1. Estrarre l'interfaccia di CardPresenceChecker creando l'interfaccia ICardPresenceChecker;
  2. Rendere esplicito che questo CardPresenceChecker funziona solo per la libreria di Società X, cambiando il suo nome in XCardPresenceChecker;
  3. Chiedi a XCardPresenceChecker di implementare ICardPresenceChecker;
  4. Estrarre la proprietà di LogInService per essere di tipo ICardPresenceChecker anziché 'sapere' esattamente quale implementazione di si tiene a bordo;
  5. E, ultimo ma non meno importante, la richiesta da parte degli utenti (altri sviluppatori) di LogInService di fornire qualsiasi classe che implementa almeno ICardPresenceChecker in modo che LogInService possa fare il suo dovere.

costruttore di LogInService assomiglia:

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

Allora, dove si forniscono LogInService con un'implementazione di ICardPresenceChecker? In genere si desidera questa "mappatura" (in questo esempio, "mappare" ICardPresenceChecker su XCardPresenceChecker) in un punto centrale all'avvio di un'applicazione, noto concettualmente come "Composizione radice". Per una normale Console Application che potrebbe essere la principale principale nella classe Program. Quindi, per questo esempio, questo pezzo di codice sarebbe stato utilizzato al posto sopracitato:

LogInService logInService = new LogInService (nuova XCardPresenceChecker());"

+1

Sebbene questo collegamento possa rispondere alla domanda, è meglio includere qui le parti essenziali della risposta e fornire il link per riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia. - [Dalla recensione] (/ recensione/post di bassa qualità/11421227) –

+0

@Nahuel lanni: Mentre apprezzo il tuo commento e cercherò di rispettare, il mio punto è che è importante leggere l'articolo per intero e non solo provare a imparare da un frammento di codice casuale. Ma ... Vedi la risposta rivista. Spero che questo ti aiuti. –

+0

IoC? Cos'è quello? :-( – Ichirichi

Problemi correlati