【问题标题】:Implementing conditional dependency injection with ninject and c#.net使用ninject和c#.net实现条件依赖注入
【发布时间】:2012-02-06 21:27:25
【问题描述】:

我正在尝试学习依赖注入 (DI) 的基础知识。为此,我编写了一个教程,通过构建 C# 控制台应用程序来演示如何使用 Ninject for DI。

该应用程序本质上旨在能够使用不同的计算方法计算购物车中物品的价值。

应用程序中的类是:

  • 一个简单的产品模型
  • 两个购物车类,充当产品集合的简单包装器
  • 一个 ValueCalculator 接口,它需要一个 ValueProducts 方法,该方法返回购物车中的部分商品总数
  • ValueCalculator 接口的两个独立实现(迭代和 LINQ 方法)

我尝试通过 .WhenInjectedTo 扩展方法使用条件注入,以便 ShoppingCart 对象将获得 LinqValueCalculator 注入,而 ShoppingCartTwo 对象将获得 IterativeValueCalulator 注入。但是,在这两种情况下都注入了 LinqValueCalculator。

见下方代码

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using Ninject;

    namespace NinjectDemo
{

// a simple product model
public class Product
{
    public int ProductID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public string Category { set; get; }
}

// calculator interface
public interface IValueCalculator
{
    decimal ValueProducts(params Product[] products);
}

// a specific implementation of the IValueCalculator using LINQ
public class LinqValueCalculator : IValueCalculator
{

    public LinqValueCalculator() {}

    public decimal ValueProducts(params Product[] products)
    {
        return (products.Sum(p => p.Price));
    }
}

// another implementation of IValueCalculator using iteration
// (*2 is to so that it returns a different result to LinqValueCalculator)
public class IterativeValueCalculator : IValueCalculator
{
    public IterativeValueCalculator() {}

    public decimal ValueProducts(params Product[] products)
    {
        decimal totalValue = 0;
        foreach (Product p in products)
        {
            totalValue += (p.Price) * 2;
        }
        return totalValue;
    }
}

// a shopping cart modelling a collection of products
public class ShoppingCart
{
    protected IValueCalculator calculator;
    protected Product[] products;

    public ShoppingCart(IValueCalculator calcParam)
    {
        calculator = calcParam;
        // define the set of products to sum
        products = new []
            {
                new Product() { Name = "Kayak", Price = 275M},
                new Product() { Name = "Lifejacket", Price = 48.95M},
                new Product() { Name = "Soccer ball", Price = 19.50M},
                new Product() { Name = "Stadium", Price = 79500M}
            };
    }

    public virtual decimal CalculateStockValue()
    {
        // calculate the total value of the products
        decimal totalValue = calculator.ValueProducts(products);
        // return the result
        return totalValue;
    }
}

// another, different, shopping cart
public class ShoppingCartTwo
{
    protected IValueCalculator calculator;
    protected Product[] products;

    public ShoppingCartTwo(IValueCalculator calcParam)
    {
        calculator = calcParam;
        // define the set of products to sum
        products = new[]
            {
                new Product() { Name = "Kayak", Price = 275M},
                new Product() { Name = "Lifejacket", Price = 48.95M},
                new Product() { Name = "Soccer ball", Price = 19.50M},
                new Product() { Name = "Stadium", Price = 79500M}
            };
    }

    public virtual decimal CalculateStockValue()
    {
        // calculate the total value of the products
        decimal totalValue = calculator.ValueProducts(products);
        // return the result
        return totalValue;
    }
}

class Program
{
    static void Main(string[] args)
    {
        IKernel ninjectKernel = new StandardKernel();

        // define the bindings
        ninjectKernel.Bind<IValueCalculator>().To<IterativeValueCalculator> ().WhenInjectedInto<ShoppingCartTwo>();
        ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();

        // create the carts and inject the dependency
        ShoppingCart cart = new ShoppingCart(ninjectKernel.Get<IValueCalculator>());
        ShoppingCartTwo cartTwo = new ShoppingCartTwo(ninjectKernel.Get<IValueCalculator>());

        // perform the calculation and write out the result
        Console.WriteLine("Total: {0:c}", cart.CalculateStockValue());
        Console.WriteLine("Total: {0:c}", cartTwo.CalculateStockValue());

        Console.Read();
    }
}
}

【问题讨论】:

  • 你有教程的链接吗?

标签: c# .net dependency-injection conditional ninject


【解决方案1】:

我认为你的问题是:-

ninjectKernel.Get<IValueCalculator>()

正在评估 它被传递到你的构造函数。

即它在其绑定上下文之外被调用。

与其自己新建对象,不如使用内核获取对象实例。

var shopCartTwo = ninjectKernel.Get<ShoppingCartTwo>();

请注意,您根本没有传递参数。 Ninject 将查看构造函数签名,确定存在未解决的依赖关系,并使用适当的上下文绑定。

【讨论】:

  • 感谢您的回复。我试过了,果然奏效了。但是,它是如何有条件的?即我必须明确要求一个 ShoppingCartTwo 对象......那么,向 ninject 询问包含注入的类的实例而不是要求它从接口解析类的想法是什么?
  • 在一个更现实的解决方案中,您可能不会处理任何购物车对象的任何具体实现。你会要求一个 IShoppingCart (使用 ShoppingCart 和 ShoppingCartTwo 实现这个)。您可能会有一些上下文绑定,告诉您在哪种情况下获取哪个。一旦解决了这个问题,ninject 就会知道要使用哪个 IValueCalculator 实现。顺便说一句,你最终的项目类型是什么?
  • 我明白了,这就是 ninject 说它可以处理“链式依赖项”时的意思。开始有意义,我发现 DI 有点抽象。可以说没有最终项目,这只是一个用于学习目的的简单控制台应用程序,除此之外没有任何计划。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-06
  • 1970-01-01
  • 1970-01-01
  • 2014-05-27
  • 2019-02-17
  • 1970-01-01
  • 2019-10-09
相关资源
最近更新 更多