zoukankan      html  css  js  c++  java
  • Pro ASP.NET MVC 5 Framework.学习笔记.6.4.MVC的必备工具

    2.5.创建链式依赖

            当你请求Ninject创建一个类型,它检查该类型的依赖是否声明。它也会检查该依赖是否依赖其他类型。如果这里有附加依赖,Ninject自动解决他们,并创建请求的所有类的实例。正是由于这样的链式依赖,它最后创建了你请求的类型的实例。

            要展示这个特性,我已经添加一个叫做DisCount的类,到Models文件夹,用它来定义一个新的接口,和该接口的一个实现。

    public interface IDiscountHelper {
        decimal ApplyDiscount(decimal totalParam);
    }
    public class DefaultDiscountHelper : IDiscountHelper {
        public decimal ApplyDiscount(decimal totalParam) {
            return (totalParam - (10m / 100m * totalParam));
        }
    }

            IDiscountHelper定义了一个ApplyDiscount方法,它对一个decimal值应用折扣。DefaultDiscounterHelper类实现了IDiscountHelper接口,应用了一个固定10%的折扣。我要修改LinqValueCalculator类,让它执行计算时,使用IDiscountHelper接口。

    public class LinqValueCalculator: IValueCalculator {
        private IDiscountHelper discounter;
        public LinqValueCalculator(IDiscountHelper discountParam) {
            discounter = discountParam;
        }
        public decimal ValueProducts(IEnumerable<Product> products) {
            return discounter.ApplyDiscount (products.Sum(p => p.Price));
        }
    }

            新的构造器声明了一个IDiscountHelper接口的依赖。我指派构造器接收的实现对象给一个字段,并在ValueProducts方法中用它对产品对象的合计值应用折扣。

            我用NinjectDependencyResolver类中的Ninject kernel绑定IDiscountHelper接口到实现类。

    private void AddBindings() {
        kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
        kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>();
    }

            我已经创建了一个依赖链。我的Home控制器依赖于IValueCalculator接口,我已经告诉Ninject用LinqValueCalculator类来解决。而LinqValueCalculator类依赖于IDiscountHelper接口,我已经告诉Ninject使用DefaultDiscountHelper类来解决。

            Ninject无缝隙地解决链式依赖。

    2.6.指定属性和构造器参数值

            在绑定接口到它的实现时,我能通过提供详细的值给属性,来配置Ninject创建的对象。要演示这个特性,我要创建修订DefaultDiscountHelper类,让他定义一个DiscountSize属性,用它来计算折扣额度。

    public interface IDiscountHelper {
        decimal ApplyDiscount(decimal totalParam);
    }
    public class DefaultDiscountHelper : IDiscountHelper {
        public decimal DiscountSize { get; set; }
        public decimal ApplyDiscount(decimal totalParam) {
            return (totalParam - (DiscountSize / 100m * totalParam));
        }
    }

            当我告诉Ninject要用接口的哪个实现时,可以使用WithPropertyValue方法,为DefaultDiscountHelper类的DiscountSize属性设置值。可以看到,我提供将属性的名字,作为字符串值设置。

    private void AddBindings() {
        kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
        kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>()
    .WithPropertyValue("DiscountSize",50M);
    }

            我不需要改变任何其他绑定,也不需要改变我使用Get方法获得ShoppingCart类的实例的方式。

            如果你有多个属性值要设置,可以使用链式调用WithPropertyValue方法。我可以用构造器参数来做同样的事情。折扣的额度作为DefaultDiscountHelper类的构造器参数。

    public interface IDiscountHelper {
        decimal ApplyDiscount(decimal totalParam);
    }
    public class DefaultDiscountHelper : IDiscountHelper {
        public decimal discountSize;
        public DefaultDiscountHelper(decimal discountParam) {
            discountSize = discountParam;
        }
        public decimal ApplyDiscount(decimal totalParam) {
            return (totalParam - (discountSize / 100m * totalParam));
        }
    }

            要使用Ninject绑定这个类,我在AddBindings方法的WithConstructorArgument方法指定构造器参数的值。

    private void AddBindings() {
        kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
        kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>()
    .WithConstructorArgument("discountParam",50M);
    }

            再一次,链式调用这些方法,提供多个值。在改变方法名称的同时,也改变了传递的参数。

    2.7.使用条件绑定

            Ninject提供一些条件绑定方法,允许我指定kernel应该用哪个类来响应特定接口的请求。要演示这点,我在Models文件夹下添加了一个FlexibleDiscountHelper类。

    public class FlexibleDiscountHelper : IDiscountHelper {
        public decimal ApplyDiscount(decimal totalParam) {
            decimal discount = totalParam > 100 ? 70 : 25;
            return (totalParam - (discount / 100m * totalParam));
        }
    }

            FlexibleDiscountHelper类基于总的数量级,应用不同的折扣。现在我需要选择IDiscountHelper接口的实现类,我可以修改NinjectDependencyResolver的AddBindings方法,来告诉Ninject。

    private void AddBindings() {
        kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
        kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>
    ().WithConstructorArgument("discountParam", 50M);
        kernel.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>()
    .WhenInjectedInto<LinqValueCalculator>();
    }

            新绑定指定当Ninject kernel创建一个LinqValueCalculator对象时,应该使用FlexibleDiscountHelper类作为IDiscountHelper接口的实现。注意,我已经有原始绑定到IDiscountHelper。Ninject试着找到最匹配的。Ninject支持一组不同条件绑定方法,最有用的是下面的:

    Method Effect
    When(条件) 当条件——lambda表达式等于true时
    WhenClassHas<T>() 当要被注入的类含有一个T类型的属性时
    WhenInjectedInto<T>() 当要被注入的类是T类型时

    2.8.设置对象目标

            Ninject最后一个特性,帮助制作对象的生命周期。默认地,Ninject在每个对象需要解决每个依赖每次你请求一个对象时,它都会创建一个新的实例。

            要演示发生了什么,我已经修改了LinqValueCalculator类的构造器,当一个新的实例被创建时,让它输出一个消息到VS输出窗口。

    public class LinqValueCalculator : IValueCalculator {
        private IDiscountHelper discounter;
        private static int counter = 0;
        public LinqValueCalculator(IDiscountHelper discountParam) {
            discounter = discountParam;
            System.Diagnostics.Debug.WriteLine(
    string.Format("Instance {0} created", ++counter));
        }
        public decimal ValueProducts(IEnumerable<Product> products) {
            return discounter.ApplyDiscount(products.Sum(p => p.Price));
        }
    }

            System.Diagnostics.Debug类包含一组方法,可以用来输出调试消息。在查看代码如何工作时,我发现他们很有用。

            Home控制器添加了两个IValueCalculator接口的实现。

    public  HomeController(IValueCalculator  calcParam, IValueCalculator  calc2)
    {
        calc = calcParam;
    }

            我没有执行任何游泳的任务,只是请求两个接口的实现。如果运行示例,会看到Ninject创建了两个LinqValueCalculator类的实例。

    Instance 1 created
    Instance 2 created

            LinqValueCalculator可以被实例化,但是不是所有的类都能。对于一些类,你希望在整个应用中共享单一实例。另外一些,你希望为每个ASP.NET平台服务的HTTP请求,都创建一个新的实例。Ninject允许你使用目标的特性,控制对象的生命周期,你会看到对于MVC框架这是多么有用的目标:在NinjectDependencyResolver中请求目标到LinqValueCalculator类。

    using Ninject.Web.Common;
    namespace EssentialTools.Infrastructure {
    public class NinjectDependencyResolver : IDependencyResolver {
    ....
    private void AddBindings() {
    kernel.Bind<IValueCalculator>().To<LinqValueCalculator>
    ().InRequestScope();

            InRequestScope扩展方法,在Ninject.Web.Common命名空间里。它告诉Ninject,应该为每个ASP.NET服务的HTTP请求,只创建一个LinqValueCalculator类的实例。每个请求会得到它自己分离的对象,但在相同的请求里的多个依赖,会用类的相同实例解决。你可以看这个改变的影响,通过启动程序,查看VS输出窗口。它会显示Ninject只创建了一个LinqValueCalculator类的实例。如果你刷新浏览器,而不是重启程序,你会看到Ninject创建了第二个对象。Ninject提供一列不同的对象目标,最有用的是:

    Name Effect
    InTransientScope() 和没有指定目标一样,为每个依赖创建一个新的对象
    InSingletonScope()ToConstant(object) 在整个应用中共享一个单一实例。如果使用InSingletoScope,Ninject会创建实例。如果用ToConstant方法,并提供这个实例,也会在整个程序中共享单一实例。。
    InThreadScope() 在单一线程中,创建一个单一实例
    InRequestScope() 在单一HTTP请求中,创建单一实例
  • 相关阅读:
    Algorithms
    Algorithms
    再探循环神经网络
    循环神经网络(RNN)
    AI:深度学习用于文本处理
    人们怎么使用 AI 抵抗冠状病毒
    AI:拿来主义——预训练网络(二)
    AI:拿来主义——预训练网络(一)
    AI:是猫还是狗,这是个问题
    Android Studio 3.6 正式版终于发布了
  • 原文地址:https://www.cnblogs.com/msdynax/p/3672067.html
Copyright © 2011-2022 走看看