IL实现简单的IOC容器

2016-12-26 19:20:02来源:cnblogs.com作者:dw-l-y-q人点击

   既然了解了IL的接口和动态类之间的知识,何不使用进来项目实验一下呢?而第一反应就是想到了平时经常说的IOC容器,在园子里搜索了一下也有这类型的文章http://www.cnblogs.com/kklldog/p/3395641.html,借鉴一下前人的知识就来实现一下吧。IOC的概念就不介绍了,想了解的同学就百度一下。

一、定义接口

  首先自定义两个接口和实现

    public interface IAnimal    {        string Cat();        string Dog();    }    public class Animal:IAnimal    {        public string Cat()        {            return "I Am Cat";        }        public string Dog()        {            return "I Am Dog";        }    }
IAnimal
    public interface IMail    {        string SendMail();        string ReceiveMail();    }    public class Mail:IMail    {        public string SendMail()        {            return "Success Send";        }        public string ReceiveMail()        {            return "Success Receive";        }    }
IMail

二、配置

  这里我就直接写一个方法来进行配置,不再定义接口了

        public Dictionary<string,string> GetAllConfig()        {            Dictionary<string, string> dic = new Dictionary<string, string>();            dic.Add("IOC.Interface.IMail", "IOC.Interface.Mail,IOC");            dic.Add("IOC.Interface.IAnimal", "IOC.Interface.Animal,IOC");            return dic;        }
Config

三、反射实现

        public static object GetInstance(string InterfaceName)        {            //已经存在的对象直接使用            if (dicObj.ContainsKey(InterfaceName))            {                return dicObj[InterfaceName];            }            var dicConfig = new Config.Config().GetAllConfig();            if (!dicConfig.ContainsKey(InterfaceName))            {                throw new Exception("未配置");            }            var config = dicConfig[InterfaceName];            Type taskType = Type.GetType(config);           // var taskObj1 = CreateInstance(taskType);            var taskObj= CreateInstanceByEmit(taskType);            if (null == taskObj)                throw new Exception("实例化接口错误");            dicObj.Add(InterfaceName, taskObj);            return taskObj;        }
GetInstance
        private static Object CreateInstance(Type taskType)        {            Stopwatch stopWatch = new Stopwatch();            stopWatch.Start();            object taskObj = Activator.CreateInstance(taskType);            stopWatch.Stop();            TimeSpan ts = stopWatch.Elapsed;            string elapsedTime = String.Format("{0}",ts.Ticks );            Console.WriteLine("CreateInstance RunTime " + elapsedTime);            return taskObj;        }
CreateInstance

通过传入接口,再去配置列表中找到对应的实现进行实例化。如果存在就直接使用实例化后的对象

四、Emit实现

要想知道Emit是如何获取接口对应实例化的对象,可以先进行一下的尝试。比如我要获取IAnimal接口实例化的对象

        public IAnimal GetInterface()        {            var realize= new Animal();            return (IAnimal)realize;        }

通过反编译工具得到以下的IL信息

IL解释:

L_0001:创建一个新的对象(构造函数)到计算堆栈上

L_0006-L_0007:先存储到指定位置再获取推送到计算堆栈上(实现中可省略)

L_0008-L_000b:同样是先存储到指定位置再获取推送到堆栈上(实现中可省略),br.s跳转到L_000b执行(针对这段IL没必要用到这个操作)

L_000c:返回

然后我们可以通过IL代码进行实现

        private static Object CreateInstanceByEmit(Type taskType)        {            Stopwatch stopWatch = new Stopwatch();            stopWatch.Start();            BindingFlags defaultFlags = BindingFlags.Public | BindingFlags.Instance;            var constructor = taskType.GetConstructors(defaultFlags)[0];//获取默认构造函数            var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString("N"), typeof(Object), new[] { typeof(object[]) }, true);            ILGenerator IL = dynamicMethod.GetILGenerator();            IL.Emit(OpCodes.Newobj, constructor);            if (constructor.ReflectedType.IsValueType)                IL.Emit(OpCodes.Box, constructor.ReflectedType);            IL.Emit(OpCodes.Ret);            //关联方法            var func = (Func<Object>)dynamicMethod.CreateDelegate(typeof(Func<Object>));            stopWatch.Stop();            TimeSpan ts = stopWatch.Elapsed;            string elapsedTime = String.Format("{0}", ts.Ticks);            Console.WriteLine("CreateInstanceByEmit RunTime " + elapsedTime);            return func.Invoke();        }
CreateInstanceByEmit

五、执行

IAnimal iMail = ServiceTaker.GetService<IOC.Interface.IAnimal>();Console.WriteLine(iMail.Cat());

通过以上的例子算是对Emit加深一下了解,也可以了解一下IOC的实现,当然IOC还有其他东西需要注意这就不一一介绍了。有兴趣的同学也欢迎来进行交流

源码:IOC

 

=============================================================

在实例化对象过程中,发现反射执行的速度还是优于Emit的,在参考http://kb.cnblogs.com/page/171668/发现反射和Emit对比在性能上也还是有差距的。这块为什么会产生这些差异在之后学习再进行分享。也请知道的园友给点指导!

 

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台