2012-04-10 81 views
3

我正在学习如何使用nInject来开发我正在开发的新应用程序,并且我已经创建了以下示例代码,可以将其复制/粘贴到简单的控制台应用程序中。它成功返回IFoo的一个实例,但我有一个问题。如何使用Ninject在子类中创建实例?

我该如何修改代码以使FooManager类创建Foo对象的实例而不执行“新建”。内核是否也要注入?但是如果注入了内核并且我将行更改为var foo = _kernel.Get<IFoo>(),是不是引入了服务定位器反模式?

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

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

回答

4

首先你必须考虑Foo的目的。这是某种数据容器还是某种服务?

在第一种情况下,您的代码完美无瑕。 Datacontainer没有依赖关系,不应该由IoC容器创建。

在第二种情况下阅读有关Ninject.Extensions.Factory。

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

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

+0

谢谢。我也和工厂一起玩过,但最后它似乎是一个围绕着核心的包装,并且仍然必须到处通过。由于我使用Foo作为Datacontainer,因此您的评论让我感到安慰,在这种情况下使用'新'是可以的! :) – 2012-04-11 13:31:23

2

有几种方法可以消除这种依赖性。您可以对数据库依赖关系执行相同的操作,并使用构造函数注入。你可以做财产注入(https://github.com/ninject/ninject/wiki/Injection-Patterns)。另一种方式,也许你正在寻找的是服务地点。要做到这一点,你可以更新你的FooManager ctor来需要一个IKernel。这将自动解决,然后您可以使用传入的内核来获取Foo。

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

是不是注射籽粒为服务定位的反模式?但如果你不这样做,那么你必须注入一个IFoo的实例。这对我来说真的很奇怪。我现在非常重视这个概念。 – 2012-04-10 15:52:12

+1

@John那么你可以创建一个工厂,如果你想要建立一个foo对象并作为IFoo返回。是的服务地点通常被认为是反模式,但这并不意味着它总是不好,可能是正确的决定。 – 2012-04-10 15:57:10