【问题标题】:How to use Ninject to create instances in child classes?如何使用 Ninject 在子类中创建实例?
【发布时间】:2023-03-12 10:42:01
【问题描述】:

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

我将如何修改代码以让 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; }
    }

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

【问题讨论】:

    标签: dependency-injection inversion-of-control ninject


    【解决方案1】:

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

    在第一种情况下,您的代码就像它一样完美。数据容器没有依赖关系,不应由 IoC 容器创建。

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

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

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

    【讨论】:

    • 谢谢。我也玩过工厂,但最后它似乎只是内核的包装,仍然必须到处传递。由于我使用 Foo 作为数据容器,您的评论让我感到安慰,在这种情况下使用“新”是可以的! :)
    【解决方案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;
        }
    }
    

    【讨论】:

    • 为服务定位器注入内核不是一种反模式吗?但是如果你不这样做,那么你必须注入一个 IFoo 的实例。这对我来说真的很奇怪。我现在非常关注这个概念。
    • @John 如果你愿意,你可以创建一个工厂来构建一个 foo 对象并作为 IFoo 返回。是的,服务位置通常被认为是一种反模式,但这并不意味着它总是不好的并且可能是正确的决定。
    猜你喜欢
    • 1970-01-01
    • 2016-09-18
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    相关资源
    最近更新 更多