zoukankan      html  css  js  c++  java
  • ASP.NET 5:依赖注入

    ASP.NET 5:依赖注入

    1.背景

        如果某个具体的(或类)对象被客户程序所依赖,通常把它们抽象成抽象类或接口。简单说,客户程序摆脱所依赖的具体类型,称之为面向接口编程。

        那么问题来了?如何选择客户程序所需要的实现类?在使用创建型模式下创建对象是不难解决这个问题。

        但如果设计的不是具体业务逻辑,而是公共类库或框架程序,对外只提供抽象而已,该如何把外部使用的类型传递给它们?

        我们可以采用“依赖注入”的方式,将加工好的抽象类型实体“注入”到客户程序中。

        注:依赖注入DI(Dependency Injection),它和控制反转IOC(Inversion of Control)是同一个意思,不同术语叫法。

    2.场景

        客户程序获取年份,我们先设计一个接口:

    复制代码
    using System;
    
    namespace Blog.Consoles
    {
        public interface ITimeProvider
        {
            DateTime CurrentDate { get; }
        }
    }
    复制代码

        并对这个接口实现(可以多种实现哦,这也是设计接口的原因):

    复制代码
    using System;
    
    namespace Blog.Consoles
    {
        public class TimeProvider : ITimeProvider
        {
            public DateTime CurrentDate
            {
                get { return DateTime.Now; }
            }
        }
    }
    复制代码

          那么我们在客户程序使用:

    复制代码
    using System;
    
    namespace Blog.Consoles
    {
        class Program
        {
            static void Main(string[] args)
            {
                ITimeProvider tp = new TimeProvider();
                Console.WriteLine(tp.CurrentDate.Year);
    
                Console.ReadKey();
            }
        }
    }
    复制代码

           这样实现的依赖关系是:

           

           显然这样客户程序还需要知道具体类型TimeProvider,我们增加一个对象:

    复制代码
    using System;
    using System.Collections.Generic;
    
    namespace Blog.Consoles
    {
        public class Assembler
        {
            //保存抽象类型和实体类型
            static Dictionary<Type, Type> d = new Dictionary<Type, Type>();
    
            static Assembler()
            {
                //注册抽象类型需要使用的实体类型
                d.Add(typeof(ITimeProvider), typeof(TimeProvider));
            }
    
            public object Create(Type type)
            {
                if ((type == null) || !d.ContainsKey(type))
                {
                    throw new NullReferenceException();
                }
    
                return Activator.CreateInstance(d[type]);
            }
    
            public T Create<T>()
            {
                return (T)Create(typeof(T));
            }
        }
    }
    复制代码

          此时再改造依赖关系:

          

          这样客户程序只依赖Assembler和ITimeProvider,并不知道TimeProvider存在。

          接下来如何写注入代码?下面分几种方式。

    3.构造注入

          构造注入使用构造方法,通过Assembler或其它机制把抽象类型作为参数传递。其实现代码:

    复制代码
    using System;
    
    namespace Blog.Consoles
    {
        class Program
        {
            public ITimeProvider _tp;
            public Program(ITimeProvider tp)
            {
                _tp = tp;
            }
    
            public int GetYear()
            {
                return _tp.CurrentDate.Year;
            }
    
            static void Main(string[] args)
            {
                ITimeProvider time = new Assembler().Create<ITimeProvider>();
                Program p = new Program(time);
                Console.WriteLine(p.GetYear()); 
    
                Console.ReadKey();
            }
        }
    }
    复制代码

    4.设置注入

          通过属性方法赋值实现的,相对于构造方法一次性注入的方式,设置注入可以在需要时有更改的机会。实现代码:

    复制代码
    using System;
    
    namespace Blog.Consoles
    {
        class Program
        {
            public ITimeProvider _tp { get; set; }
    
            public int GetYear()
            {
                return _tp.CurrentDate.Year;
            }
    
            static void Main(string[] args)
            {
                ITimeProvider time = new Assembler().Create<ITimeProvider>();
    
                Program p = new Program();
                p._tp = time;
    
                Console.WriteLine(p.GetYear());
    
                Console.ReadKey();
            }
        }
    }
    复制代码

           还可以简写: 

    复制代码
    using System;
    
    namespace Blog.Consoles
    {
        class Program
        {
            public ITimeProvider _tp { get; set; }
    
            public int GetYear()
            {
                return _tp.CurrentDate.Year;
            }
    
            static void Main(string[] args)
            {
                var p = new Program() { _tp = new Assembler().Create<ITimeProvider>() };
    
                Console.WriteLine(p.GetYear());
    
                Console.ReadKey();
            }
        }
    }
    复制代码

    5.MEF注入

        导出部件:

        

        下面不使用Assembler对象,实现代码:

    复制代码
    using System;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Reflection;
    
    namespace Blog.Consoles
    {
        class Program
        {
            private static CompositionContainer container;
    
            private void Compose()
            {
                var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
                container = new CompositionContainer(catalog);
                //将部件和宿主程序添加到组合容器
                container.ComposeParts(this, new TimeProvider());
            }
    
            //导入部件
            [Import]
            public ITimeProvider _tp { get; set; }
    
            public int GetYear()
            {
                return _tp.CurrentDate.Year;
            }
    
            static void Main(string[] args)
            {
                var p = new Program();
                p.Compose();
                
                Console.WriteLine(p.GetYear());
    
                Console.ReadKey();
            }
        }
    }
    复制代码

     6.ASP.NET 5注入

           修改Startup.cs:

           

          测试:

          

    7.小结

          关于依赖注入的方式,还有接口注入,自定义特性等(它们之间区别和选择,自行体会或查资料),不常用就不说了。

          感受到ASP.NET 5自带DI爽就行啦!(ASP.NET 5真的海皮啦!)

          后面的帖子,进入项目实战了,最近比较忙,请园友保持耐心。

      

     
    分类: DotNet 2015
  • 相关阅读:
    awk 入门教程【转】
    xargs 命令教程【转】
    redis 执行lua脚本
    SpringMVC 执行过程分析
    EurekaClient 服务注册、发现、续约
    Springboot 自动配置 & 自定义Starter
    Netty 实现HttpServer
    Spring中@Import 用法
    Netty自定义任务&Future-Listener机制
    Springboot + Netty + WebSocket 实现简单的聊天
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4351243.html
Copyright © 2011-2022 走看看