2012-04-10 8 views
3

Ich lerne, nInject für eine neue Anwendung, die ich entwickle, zu verwenden, und ich habe den folgenden Beispielcode erstellt, der in eine einfache Konsolenanwendung kopiert/eingefügt werden kann. Es gibt erfolgreich eine Instanz von IFoo zurück, aber ich habe eine Frage dazu.Wie Ninject verwenden, um Instanzen in untergeordneten Klassen zu erstellen?

Wie würde ich den Code ändern, damit die FooManager-Klasse eine Instanz des Foo-Objekts erstellt, ohne ein 'new' auszuführen. Muss der Kern auch gespritzt werden? Aber wenn der Kern injiziert wird und ich die Zeile ändern, um var foo = _kernel.Get<IFoo>() zu lesen, führt das nicht zu einem Service-Locator-Anti-Pattern?

namespace IOCTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      using (IKernel kernel = new StandardKernel(new StandardModule())) 
      { 
       // do something with the kernal 
       var mgr = kernel.Get<IFooManager>(); 
       var foo = mgr.GetById(1); 
      } 
     } 
    } 

    public class StandardModule : Ninject.Modules.NinjectModule 
    { 
     public override void Load() 
     { 
      Bind<IDatabase>() 
       .To<Database>() 
       .InTransientScope(); 

      Bind<IFooManager>() 
       .To<FooManager>() 
       .InTransientScope(); 
     } 
    } 

    //****************************************************** 

    public interface IDatabase 
    { 
     object[] GetScalar(int id); 
    } 

    public class Database : IDatabase 
    { 
     public object[] GetScalar(int id) 
     { 
      return new object[] { "RowName" }; 
     } 
    } 

    //****************************************************** 

    public interface IFooManager 
    { 
     IFoo GetById(int id); 
    } 

    public class FooManager : IFooManager 
    { 
     private IDatabase _db; 

     public FooManager(IDatabase db) { _db = db; } 

     public IFoo GetById(int id) 
     { 
      var results = _db.GetScalar(id); 
      var foo = new Foo(); // <-- HOW DO I ELIMINATE THIS DEPENDENCY? 
      foo.Name = results[0].ToString(); 
      return foo; 
     } 
    } 

    //****************************************************** 

    public interface IFoo 
    { 
     string Name { get; set; } 
    } 

    public class Foo : IFoo 
    { 
     public string Name { get; set; } 
    } 

    //****************************************************** 
} 

Antwort

4

Zuerst müssen Sie über den Zweck von Foo nachdenken. Ist das eine Art Datencontainer oder Service?

Im ersten Fall ist Ihr Code perfekt wie er ist. Datencontainer haben keine Abhängigkeiten und sollten nicht vom IoC-Container erstellt werden.

Im zweiten Fall lesen Sie über Ninject.Extensions.Factory.

http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-introduction/

https://github.com/ninject/ninject.extensions.factory/wiki

+0

Danke. Ich hatte auch mit der Fabrik gespielt, aber am Ende schien es nur ein Wrapper um den Kern herum zu sein und musste immer noch überall hin geführt werden. Da ich Foo als Datencontainer benutze, bringt mich dein Kommentar zum Trost, dass es ok ist, in diesem Fall 'neu' zu verwenden! :) –

2

Es gibt mehrere Möglichkeiten, diese Abhängigkeit zu beseitigen. Sie könnten das gleiche tun, was Sie mit der Datenbankabhängigkeit getan haben, und die Konstruktorinjektion verwenden. Sie könnten eine Property-Injektion durchführen (https://github.com/ninject/ninject/wiki/Injection-Patterns). Ein anderer Weg, und vielleicht, was Sie suchen, würde Dienstort sein. Um dies zu tun, können Sie Ihren FooManager ctor so aktualisieren, dass ein IKernel erforderlich ist. Dies wird automatisch gelöst und Sie können dann den Kernel verwenden, der übergeben wurde, um Foo zu erhalten.

public class FooManager : IFooManager 
{ 
    private IDatabase _db; 
    private IKernel _kernel; 

    public FooManager(IDatabase db, IKernel kernel) { _db = db; _kernel = kernel;} 

    public IFoo GetById(int id) 
    { 
     var results = _db.GetScalar(id); 
     // var foo = new Foo(); // <-- HOW DO I ELIMINATE THIS DEPENDENCY? 
     var foo = kernel.Get<IFoo>(); // Like this perhaps 
     foo.Name = results[0].ToString(); 
     return foo; 
    } 
} 
+1

Injektion ist nicht die Kernal für Service-Locator ein Anti-Muster? Aber wenn Sie das nicht tun, müssen Sie eine Instanz von IFoo injizieren. Das erscheint mir wirklich seltsam. Ich bin gerade sehr auf dieses Konzept konzentriert. –

+1

@John Nun, Sie könnten eine Fabrik erstellen, wenn Sie wollten, um ein foo-Objekt aufzubauen und als IFoo zurückzukehren. Yes Service-Standort wird in der Regel als ein Anti-Muster, aber das bedeutet nicht, dass es immer schlecht ist und die richtige Entscheidung sein kann. –

Verwandte Themen