利用Unity和C#特性实现自动注入(依赖注入)

公司目前使用的依赖注入框架是Unity,所以就对这个框架进行了对应的学习,网上也有比较多的资料,不过注入方面大部分都是偏向于构造器注入、属性注入和方法注入等,好像还没有自动注入相关的文章,所以就有了本文。

测试环境:

vistual  studio 2017

.net framework的版本为4.6.1

Demo源码:https://gitee.com/zxy15914507674/shared_resource_name/blob/master/依赖注入.rar 

步骤(下面定义了那么多层是为了可扩展性):

一   新增类库项目,名为 '接口层'

1  定义接口ITestInterface1,并编写如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 接口层
{
    public interface ITestInterface1
    {
        void TestMethod();
    }
}

2  添加NuGet包, 搜索Unity并且安装,如下图(由于我的已经安装过了,就显示卸载):

3  定义特性类DefaultAttribute,并编写如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity;
using Unity.Lifetime;

namespace 接口层
{
    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
    public class DefaultAttribute : Attribute
    {
        public DefaultAttribute(Type registerAs)
        {
            this.RegisterAs = registerAs;
        }
        public Type RegisterAs { get; private set; }

        /// <summary>
        /// 进行注入
        /// </summary>
        /// <param name="container"></param>
        /// <param name="type"></param>
        public void OnVisit(IUnityContainer container, Type type)
        {
            if (type.IsAbstract) throw new ArgumentException(string.Format("虚拟类型{0}不能注册为服务实例。", type));

            container.RegisterType(RegisterAs, type, new ContainerControlledLifetimeManager());
        }
    }
}

4  定义类UnityRoot,目的是实例化容器,编辑如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity;

namespace 接口层
{
    //这里的UnityRoot类正常情况下不应该放在接口层,应该放到主程序能访问到的层,现在放在这里是为了方便测试 
    public class UnityRoot
    {
        public static IUnityContainer container = new UnityContainer();
    }
}

二    新建类库项目,名为  ' 接口实现层' 

1   添加‘接口层’ 的项目引用

2   新建类TestClass1来实现前面接口层的接口ITestInterface1,并编辑如下:

using System.Text;
using System.Threading.Tasks;
using 接口层;

namespace 接口实现层
{
    [Default(typeof(ITestInterface1))]
    public class TestClass1 : ITestInterface1
    {
        public void TestMethod()
        {
            Console.WriteLine("TestClass1类中的TestMethod方法");
        }
    }
}

3  生成前面所建立的两个项目

三    实现自动注入和测试

1   新建控制台项目作为测试项目,名为‘依赖注入’,并设为启动项目

2   添加 ‘接口层’  的项目引用

3   添加NuGet包, 安装Unity

4  主程序编写如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using 接口层;
using Unity;

namespace 依赖注入
{
    class Program
    {
       
        static void Main(string[] args)
        {
            #region 实现自动注入
            //通过反射获取接口实现层.dll程序集中所有的Type,当然程序集的路径可以保持在数据库中
            //需要替换成对应得路径
            Assembly assembly = Assembly.LoadFile("F:\\vs2017Project\\依赖注入\\接口实现层\\bin\\Debug\\接口实现层.dll");
            IList<Type> types = assembly.GetTypes();

            //定义集合,存储在接口上标注DefaultAttribute的Type
            IList<KeyValuePair<DefaultAttribute, Type>> items = new List<KeyValuePair<DefaultAttribute, Type>>();
            foreach (Type type in types)
            {
                foreach (DefaultAttribute attr in type.GetCustomAttributes(typeof(DefaultAttribute), true))
                {
                    items.Add(new KeyValuePair<DefaultAttribute, Type>(attr, type));
                }
            }

            try
            {
                foreach (KeyValuePair<DefaultAttribute, Type> kvp in items)
                {
                    //进行注入
                    (kvp.Key).OnVisit(UnityRoot.container, kvp.Value);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("自动注入出错");
            }
            #endregion




            #region 测试(从容器中获取对象)
            //测试:从容器中获取对象
            ITestInterface1 testInterface1 = UnityRoot.container.Resolve<ITestInterface1>();
            testInterface1.TestMethod();

           
            Console.Read();

            #endregion
        }
        
    }
}

5   运行效果如下图:

后期要扩展就方便多了,如在接口层新增接口ITestInterface2,在接口实现层新增接口ITestInterface2实现类TestClass2

接口ITestInterface2如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 接口层
{
    public interface ITestInterface2
    {
        void TestMethod();
    }
}

接口实现类TestClass2:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 接口层;

namespace 接口实现层
{
    [Default(typeof(ITestInterface2))]
    public class TestClass2 : ITestInterface2
    {
        public void TestMethod()
        {
            Console.WriteLine("TestClass2类中的TestMethod方法");
        }
    }
}

主程序测试如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using 接口层;
using Unity;

namespace 依赖注入
{
    class Program
    {
       
        static void Main(string[] args)
        {
            #region 实现自动注入
            //通过反射获取接口实现层.dll程序集中所有的Type,当然程序集的路径可以保持在数据库中
            //需要替换成对应得路径
            Assembly assembly = Assembly.LoadFile("F:\\vs2017Project\\依赖注入\\接口实现层\\bin\\Debug\\接口实现层.dll");
            IList<Type> types = assembly.GetTypes();

            //定义集合,存储在接口上标注DefaultAttribute的Type
            IList<KeyValuePair<DefaultAttribute, Type>> items = new List<KeyValuePair<DefaultAttribute, Type>>();
            foreach (Type type in types)
            {
                foreach (DefaultAttribute attr in type.GetCustomAttributes(typeof(DefaultAttribute), true))
                {
                    items.Add(new KeyValuePair<DefaultAttribute, Type>(attr, type));
                }
            }

            try
            {
                foreach (KeyValuePair<DefaultAttribute, Type> kvp in items)
                {
                    //进行注入
                    (kvp.Key).OnVisit(UnityRoot.container, kvp.Value);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("自动注入出错");
            }
            #endregion




            #region 测试(从容器中获取对象)
            //测试:从容器中获取对象
            ITestInterface1 testInterface1 = UnityRoot.container.Resolve<ITestInterface1>();
            testInterface1.TestMethod();

            ITestInterface2 testInterface2 = UnityRoot.container.Resolve<ITestInterface2>();
            testInterface2.TestMethod();
            Console.Read();

            #endregion
        }
        
    }
}

效果图如下图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zxy2847225301

测试使用

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值