网址:https://blog.csdn.net/wangyahua1234/article/details/100619695

目录

1. IoC简介

2. Tiny版IoC的功能

3. Tiny版IoC的实现

3.1 定制属性

3.2 IoC实现

4. Tiny版IoC的使用

5. 参考

1. IoC简介

IoC(Inversion of Control)翻译为“控制翻转”,这个“翻转”指的“获得依赖对象的过程被翻转了”。

 

IoC思想出现之前,我们想实例化一个对象,就必须在需要的地方new这个对象,然后才能使用这个对象中的成员。这样做的虽然很方便,但是久而久之代码中到处都是分散new的对象,且每个对象的生命周期都无法得到有效管理,最终导致对象管理成为项目开发的一个沉重的包袱。

 

如何摆脱这种困境呢——那就专门找一个模块做这个事情,这个模块就是IoC容器(容器是一种形象的说法,IoC就像一个碗,里面可以盛放对象,想要对象,不要再到处new了,直接从这个碗里面取)。

 

IoC的实现使得获取依赖对象的过程由自身管理变为由IoC主动注入,因此,IoC还有一个更容易理解的别名“依赖注入”。

 

2. Tiny版IoC的功能

目前有大量的IoC实现框架,比如Java Spring框架,.NET autofac框架,这些框架非常强大,本身的功能已经超出最初IoC设计的初衷,熟练使用起来还是需要费一些时间的。如果你的项目不是很庞大,但是也想好好管理对象,使代码清晰结构模块化,不妨自己来实现一个IoC容器。

 

下面给出的Tiny版IoC容器实现具有以下功能:

 

支持类的定制属性,指定其是否可被IoC容器扫描,以及如何实例化。

支持对象的单实例化(仅限默认构造函数)和多实例化;

以上两点基本可以满足部分中小型项目开发的应用场景了。

 

3. Tiny版IoC的实现

开发之前,你需要一些.NET for C#语言的知识储备:

 

定制属性

反射

泛型

IoC实现的核心,是“反射”机制。“定制属性”和“泛型”只是帮助你开发出可配置、通用化的、更好用的IoC容器。

 

3.1 定制属性

using System;

/// <summary>

/// 自定义类使用本定制属性时,将会被Ioc扫描,默认进行单实例化

/// 自定义类不使用本定制属性或使用本定制属性且带入"MultiInstance"参数,将会执行多实例化

/// </summary>

[AttributeUsage(AttributeTargets.Class)]

public class DependenceInjection : Attribute

{

    public string InstanceType { get; set; }

    /// <summary>

    /// SingleInstance 单实例初始化,应用程序生命周期内只初始化一次;默认为单实例初始化。

    /// MultiInstance 多实例初始化,每次调用,都将重新初始化一次。

    /// </summary>

    /// <param name="instanceType"></param>

    public DependenceInjection(string instanceType = "SingleInstance")

    {

        this.InstanceType = instanceType;

    }

}

3.2 IoC实现

说明:

 

利用反射机制获取程序集中的所有包含定制属性标记的类型;

根据定制属性类型进行实例化;

将该实例化对象,存放到IoC容器字典中;

单实例化对象,直接从IoC容器中取;

多实例化对象,也可由IoC代理进行自定义构造。

using System;

using System.Collections.Generic;

using System.Reflection;

using System.IO;

/// <summary>

    /// 简易IoC容器类,可以通过定制属性DependenceInjection,来指定需要IoC容器扫描的类

    /// </summary>

    public static class IocHelper

    {

        public static Dictionary<Type, object> IocContainer = new Dictionary<Type, object>();

 

        /// <summary>

        /// 检索指定路径的程序集,注册带定制属性的类到IoC容器中

        /// </summary>

        /// <param name="assemblyPath">指定路径的程序集</param>

        public static void Register(string assemblyPath)

        {

            if (Path.GetExtension(assemblyPath) != ".exe" && !File.Exists(assemblyPath))

                throw new Exception(string.Format("程序集({0})不存在!", assemblyPath));

            try

            {

                Assembly asb = Assembly.LoadFrom(assemblyPath);

                var objetcList = asb.GetTypes();

 

                if (objetcList.Any())

                {

                    foreach (var obj in objetcList)

                    {

                        if (DoSingleInstance(obj))

                        {

                            //如果该类包含定制的属性且为要求执行单实例,则直接实例化

                            var objectInstance = Activator.CreateInstance(obj, null);

                            if (objectInstance != null)

                                IocContainer.Add(obj, objectInstance);

                            else

                                throw new Exception(string.Format("实例化对象{0}失败!", obj));

                        }

 

                    }

                }

               

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

 

        /// <summary>

        /// 判断执行单实例化还是多实例化

        /// </summary>

        /// <param name="type"></param>

        /// <returns></returns>

        private static bool DoSingleInstance(Type type)

        {

            Attribute[] attrs = Attribute.GetCustomAttributes(type);

 

            foreach (var attr in attrs)

            {

                if (attr is DependenceInjection)

                {

                    var di = (DependenceInjection)attr;

                    if (di.InstanceType == "SingleInstance")

                    {

                        return true;

                    }

                }

            }

 

            return false;

        }

 

        /// <summary>

        /// 实例化:

        ///     单实例使用默认构造函数

        ///     多实例可以自定义构造函数

        /// </summary>

        /// <typeparam name="T"></typeparam>

        /// <param name="args"></param>

        /// <returns></returns>

        public static T Resolve<T>(params object[] args)

        {

            if (DoSingleInstance(typeof(T)))

            {

                if (IocContainer.ContainsKey(typeof(T)))

                    return (T)IocContainer[typeof(T)];

            }

            else

            {

                return (T)Activator.CreateInstance(typeof(T), args);

            }

 

            return default(T);

        }

    }

4. Tiny版IoC的使用

比较方便的使用场景是:直接让IoC扫描自己所在的应用程序,在程序运行的最开始处,注册应用程序中满足定制属性条件的对象。因为可以定制类的属性,因此我们可以做到IoC在扫描的时候,不会扫描到自己。

 

//User类被定制为可被IoC扫描的类,且只能单实例化(是用来默认参数)

[DependenceInjection()]

    public class User

    {

        public void SayHello()

        {

            Console.WriteLine("Hello!");

        }

    }

 

//Book类没有被定制,因此不可被IoC扫描,但是可以由IoC代理进行构造初始化

    public class Book

    {

        public void GetName()

        {

            Console.WriteLine("《哈利波特》");

        }

    }

 

//Book类被定制为可被IoC扫描的类,且可以多实例化

    [DependenceInjection("MultyInstance")]

    public class Food

    {

        public Food(string name)

        {

            Name = name;

        }

 

        public string Name { get; set; }

        public void GetName()

        {

            Console.WriteLine(Name);

        }

    }

 

public class Program

    {

        public static void Main(string[] args)

        {

        //编译生成的程序集IoC.exe路径

            IocHelper.Register(@"C:\Users\Administrator\Documents\Visual Studio 2015\Projects\IoC\IoC\bin\Debug\IoC.exe");

 

            var user = IocHelper.Resolve<User>();

            user?.SayHello();

 

            var book = IocHelper.Resolve<Book>();

            book?.GetName();

 

            var food1 = IocHelper.Resolve<Food>("榴莲饼");

            food1?.GetName();

 

            var food2 = IocHelper.Resolve<Food>("烤香肠");

            food2?.GetName();

 

            Console.ReadKey();

        }

    }

执行,得到了你想要的实例化结果:

 

 

目录1. IoC简介2. Tiny版IoC的功能3. Tiny版IoC的实现3.1 定制属性3.2 IoC实现4. Tiny版IoC的使用5. 参考1. IoC简介IoC(Inversion of Control)翻译为“控制翻转”,这个“翻转”指的“获得依赖对象的过程被翻转了”。
IoC思想出现之前,我们想实例化一个对象,就必须在需要的地方new这个对象,然后才能使用这个对象中的成员。这样做的虽然很方便,但是久而久之代码中到处都是分散new的对象,且每个对象的生命周期都无法得到有效管理,最终导致对象管理成为项目开发的一个沉重的包袱。
如何摆脱这种困境呢——那就专门找一个模块做这个事情,这个模块就是IoC容器(容器是一种形象的说法,IoC就像一个碗,里面可以盛放对象,想要对象,不要再到处new了,直接从这个碗里面取)。
IoC的实现使得获取依赖对象的过程由自身管理变为由IoC主动注入,因此,IoC还有一个更容易理解的别名“依赖注入”。
2. Tiny版IoC的功能目前有大量的IoC实现框架,比如Java Spring框架,.NET autofac框架,这些框架非常强大,本身的功能已经超出最初IoC设计的初衷,熟练使用起来还是需要费一些时间的。如果你的项目不是很庞大,但是也想好好管理对象,使代码清晰结构模块化,不妨自己来实现一个IoC容器。
下面给出的Tiny版IoC容器实现具有以下功能:
支持类的定制属性,指定其是否可被IoC容器扫描,以及如何实例化。支持对象的单实例化(仅限默认构造函数)和多实例化;以上两点基本可以满足部分中小型项目开发的应用场景了。
3. Tiny版IoC的实现开发之前,你需要一些.NET for C#语言的知识储备:
定制属性反射泛型IoC实现的核心,是“反射”机制。“定制属性”和“泛型”只是帮助你开发出可配置、通用化的、更好用的IoC容器。
3.1 定制属性using System;/// <summary>/// 自定义类使用本定制属性时,将会被Ioc扫描,默认进行单实例化/// 自定义类不使用本定制属性或使用本定制属性且带入"MultiInstance"参数,将会执行多实例化/// </summary>[AttributeUsage(AttributeTargets.Class)]public class DependenceInjection : Attribute{    public string InstanceType { get; set; }    /// <summary>    /// SingleInstance 单实例初始化,应用程序生命周期内只初始化一次;默认为单实例初始化。    /// MultiInstance 多实例初始化,每次调用,都将重新初始化一次。    /// </summary>    /// <param name="instanceType"></param>    public DependenceInjection(string instanceType = "SingleInstance")    {        this.InstanceType = instanceType;    }}12345678910111213141516171819203.2 IoC实现说明:
利用反射机制获取程序集中的所有包含定制属性标记的类型;根据定制属性类型进行实例化;将该实例化对象,存放到IoC容器字典中;单实例化对象,直接从IoC容器中取;多实例化对象,也可由IoC代理进行自定义构造。using System;using System.Collections.Generic;using System.Reflection;using System.IO;/// <summary>    /// 简易IoC容器类,可以通过定制属性DependenceInjection,来指定需要IoC容器扫描的类    /// </summary>    public static class IocHelper    {        public static Dictionary<Type, object> IocContainer = new Dictionary<Type, object>();
        /// <summary>        /// 检索指定路径的程序集,注册带定制属性的类到IoC容器中        /// </summary>        /// <param name="assemblyPath">指定路径的程序集</param>        public static void Register(string assemblyPath)        {            if (Path.GetExtension(assemblyPath) != ".exe" && !File.Exists(assemblyPath))                throw new Exception(string.Format("程序集({0})不存在!", assemblyPath));            try            {                Assembly asb = Assembly.LoadFrom(assemblyPath);                var objetcList = asb.GetTypes();
                if (objetcList.Any())                {                    foreach (var obj in objetcList)                    {                        if (DoSingleInstance(obj))                        {                            //如果该类包含定制的属性且为要求执行单实例,则直接实例化                            var objectInstance = Activator.CreateInstance(obj, null);                            if (objectInstance != null)                                IocContainer.Add(obj, objectInstance);                            else                                throw new Exception(string.Format("实例化对象{0}失败!", obj));                        }
                    }                }                           }            catch (Exception ex)            {                throw ex;            }        }
        /// <summary>        /// 判断执行单实例化还是多实例化        /// </summary>        /// <param name="type"></param>        /// <returns></returns>        private static bool DoSingleInstance(Type type)        {            Attribute[] attrs = Attribute.GetCustomAttributes(type);
            foreach (var attr in attrs)            {                if (attr is DependenceInjection)                {                    var di = (DependenceInjection)attr;                    if (di.InstanceType == "SingleInstance")                    {                        return true;                    }                }            }
            return false;        }
        /// <summary>        /// 实例化:        ///     单实例使用默认构造函数        ///     多实例可以自定义构造函数        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="args"></param>        /// <returns></returns>        public static T Resolve<T>(params object[] args)        {            if (DoSingleInstance(typeof(T)))            {                if (IocContainer.ContainsKey(typeof(T)))                    return (T)IocContainer[typeof(T)];            }            else            {                return (T)Activator.CreateInstance(typeof(T), args);            }
            return default(T);        }    }12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394954. Tiny版IoC的使用比较方便的使用场景是:直接让IoC扫描自己所在的应用程序,在程序运行的最开始处,注册应用程序中满足定制属性条件的对象。因为可以定制类的属性,因此我们可以做到IoC在扫描的时候,不会扫描到自己。
//User类被定制为可被IoC扫描的类,且只能单实例化(是用来默认参数)[DependenceInjection()]    public class User    {        public void SayHello()        {            Console.WriteLine("Hello!");        }    }
//Book类没有被定制,因此不可被IoC扫描,但是可以由IoC代理进行构造初始化    public class Book    {        public void GetName()        {            Console.WriteLine("《哈利波特》");        }    }
//Book类被定制为可被IoC扫描的类,且可以多实例化    [DependenceInjection("MultyInstance")]    public class Food    {        public Food(string name)        {            Name = name;        }
        public string Name { get; set; }        public void GetName()        {            Console.WriteLine(Name);        }    }
public class Program    {        public static void Main(string[] args)        {        //编译生成的程序集IoC.exe路径            IocHelper.Register(@"C:\Users\Administrator\Documents\Visual Studio 2015\Projects\IoC\IoC\bin\Debug\IoC.exe");
            var user = IocHelper.Resolve<User>();            user?.SayHello();
            var book = IocHelper.Resolve<Book>();            book?.GetName();
            var food1 = IocHelper.Resolve<Food>("榴莲饼");            food1?.GetName();
            var food2 = IocHelper.Resolve<Food>("烤香肠");            food2?.GetName();
            Console.ReadKey();        }    }123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657执行,得到了你想要的实例化结果:
————————————————版权声明:本文为CSDN博主「yahua_king」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/wangyahua1234/article/details/100619695

从0开始搭建一个IoC容器(C#版)的更多相关文章

  1. 手写一个IOC容器

    链接:https://pan.baidu.com/s/1MhKJYamBY1ejjjhz3BKoWQ 提取码:e8on 明白什么是IOC容器: IOC(Inversion of Control,控制反 ...

  2. 手撸一个IOC容器

    IoC 什么是IoC? IoC是Inversion of Control(控制反转)的简称,注意它是一个技术思想.描述的是对象创建.管理的事情. 传统开发方式:比如类A依赖类B,往往会在类A里面new ...

  3. 揣摩实现一个ioc容器需要做的事情

    思路: ioc框架的核心就是管理bean的生命周期,bean的生命周期包括:创建,使用,销毁. 创建 容器在创建一个bean的实例之前必须要解决以下问题:第一个问题: 创建bean的信息如何提供给你容 ...

  4. 基于Windows服务器,从0开始搭建一个基于RTSP协议的直播平台

    作案工具下载 EasyDarwin 服务端程序,用来接受推流和拉流 FFmpeg 可以用来推流视频数据到服务端,也可以从服务端拉流下来播放,也可以从一个服务端拉流下来,转推到另一个服务端去. Easy ...

  5. 从0开始搭建一个阿里云java部署环境

    一.购买服务器 https://www.aliyun.com/daily-act/ecs/activity_selection?spm=5176.8112568.738194.8.674c9ed53Y ...

  6. 搭建一个 简易的php版 todolist

    我记得以前使用 wunderlist 但是国外..后来用了半年. 挺方便的.但是.后来慢慢忘了这工具存在 缺少了todolist.效率折半.. so.我搭建了个简单的todolist.  :mytin ...

  7. 自定义模拟一个Spring IOC容器

    一.模拟一个IOC容器: 介绍:现在,我们准备使用一个java project来模拟一个spring的IOC容器创建对象的方法,也就是不使用spring的jar自动帮助我们创建对象,而是通过自己手动书 ...

  8. 曹工说Tomcat4:利用 Digester 手撸一个轻量的 Spring IOC容器

    一.前言 一共8个类,撸一个IOC容器.当然,我们是很轻量级的,但能够满足基本需求.想想典型的 Spring 项目,是不是就是各种Service/DAO/Controller,大家互相注入,就组装成了 ...

  9. 手写一个最简单的IOC容器,从而了解spring的核心原理

    从事开发工作多年,spring源码没有特意去看过.但是相关技术原理倒是背了不少,毕竟面试的那关还是得过啊! 正所谓面试造火箭,工作拧螺丝.下面实现一个最简单的ioc容器,供大家参考. 1.最终结果 2 ...

随机推荐

  1. 「CF526F」 Pudding Monsters

    CF526F Pudding Monsters 传送门 模型转换:对于一个 \(n\times n\) 的棋盘,若每行每列仅有一个棋子,令 \(a_x=y\),则 \(a\) 为一个排列. 转换成排列 ...

  2. 个人博客开发之blog-api 项目全局日志拦截记录

    前言 大型完善项目中肯定是需要一个全局日志拦截,记录每次接口访问相关信息,包括: 访问ip,访问设备,请求参数,响应结果,响应时间,开始请求时间,访问接口描述,访问的用户,接口地址,请求类型,便于项目 ...

  3. SQLITE数据库不支持远程访问

    SQLITE数据库不支持远程访问 import sqlite3 conn=sqlite3.connect("dailiaq.db") cur=conn.cursor() def c ...

  4. DEV C++5.11编译没有结果提示

    点击"视图"菜单--选择"浮动报告 窗口"

  5. Python基础之PyQt5关闭界面

    想让执行完程序后自动关闭窗口,而不用点击右上角叉叉的方法是self.close(),具体应用还是以treewidget为例. 前面我们写了一个treewidget的界面,并且实现了界面代码分离,具体实 ...

  6. Python入门 -- 001

    在Windows系统下安装python: 从Python的官方网站(http://www.python.org/)下载最新版的程序安装包. 安装完成后设置路径,使得在Windows系统的CMD中能够通 ...

  7. 【Azure API 管理】在APIM中使用客户端证书验证API的请求,但是一直提示错误"No client certificate received."

    API 管理 (APIM) 是一种为现有后端服务创建一致且现代化的 API 网关的方法. 问题描述 在设置了APIM客户端证书,用户保护后端API,让请求更安全. 但是,最近发现使用客户端证书的API ...

  8. At 、Crontabl定时任务

    之前笔者是在本地写的博客,然后用 windows 定时任务启动写的脚本上传到 Github 上,现在又遇到了 Linux 上的定时任务,项目还要用到 Quartz 定时任务框架 1. 一次性定时任务 ...

  9. HCNA Routing&Switching之交换技术基础

    什么是交换机?顾名思义,交换机就是用来数据包交换的:广泛用于终端接入:它的前身是hub(集线器),hub是一个古老的设备,它的作用也是用于终端接入,但hub有一个最大的缺点是它不能隔离冲突域:所谓冲突 ...

  10. css :nth-of-type选择器为什么不起作用!!!

    问题 今天工作才发现的,原来我一直就理解错了!! MDN官网对这个选择器的的定义是: :nth-of-type() 这个 CSS 伪类是针对具有一组兄弟节点的标签, 用 n 来筛选出在一组兄弟节点的位 ...