网址: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. 中国剩余定理简析(python实现)

    中国剩余定理CRT 正整数m1,m2,...,mk两两互素,对b1,b2,...,bk的同余式组为 \[\begin{cases} x \equiv b_1\; mod \;m_1\\ x \equi ...

  2. Day4 包机制 及JavaDoc文档.

    包机制 为了更好地组织类,java提供了包机制,用于区别类名的命名空间. 包的本质是文件夹 它语句的语法格式为: package pkg1[. pkg2 [.pkg3...] ] ; 一般利用公司域名 ...

  3. 答读者问(1):非模式物种找marker;如何根据marker定义细胞类型

    下午花了两个小时回答读者的疑问,觉得可以记录下来,也许能帮到一部分人. 第一位读者做的是非模式物种的单细胞. 一开始以为是想问我非模式物种的marker基因在哪儿找,读者朋友也提到了blast 研究的 ...

  4. 记录一些css奇淫技巧

    文本两端对齐 文字在固定宽度内两端对齐 text-align: justify; text-align-last: justify; 滤镜filter 元素(经常用作图片)置灰效果,类似disable ...

  5. P5042 丢失的题面

    P5042 丢失的题面 顺序:10 - 1 - 7 - 8 - 9 - 4 - 5 - 6 - 2 - 3 Point 10 读入,特判,输出. 读入的英文意思是让选手输出自己的程序本身,这个题的确存 ...

  6. jenkens安装教程

    war包安装方式(linux和windows下) 具体参见:https://www.cnblogs.com/UncleYong/p/10742867.html

  7. Skywalking-02:如何写一个Skywalking trace插件

    如何写一个Skywalking trace插件 javaagent 原理 美团技术团队-Java 动态调试技术原理及实践 类图 实现 ConsumeMessageConcurrentlyInstrum ...

  8. Unity3D学习笔记3——Unity Shader的初步使用

    目录 1. 概述 2. 详论 2.1. 创建材质 2.2. 着色器 2.2.1. 名称 2.2.2. 属性 2.2.3. SubShader 2.2.3.1. 标签(Tags) 2.2.3.2. 渲染 ...

  9. ifix 自动化(Automation)错误弹窗的解决方案

    在先前ifix项目中添加了语音模块,然后概率性跳出自动化(Automation)错误弹窗,先前分析了很多种原因,从代码的冗余,编码等角度进行了优化,效果不是很理想,仍然会概率性出现.经过反反复复大约3 ...

  10. Spring Data Commons 远程命令执行漏洞(CVE-2018-1273)

    影响版本 Spring Framework 5.0 to 5.0.4 Spring Framework 4.3 to 4.3.14 poc https://github.com/zhzyker/exp ...