C# IoC控制反转学习笔记

一、什么是IOC

IoC-Invertion of Control,即控制反转,是一种程序设计思想。

先初步了解几个概念:

依赖(Dependency):就是有联系,表示一个类依赖于另一个类。

依赖倒置原则(DIP):设计模式六大原则之一,是一种软件架构设计原则。

控制反转(IoC):一种软件设计原则,上层对下层的依赖(即底层模块的获得)交给第三方。

依赖注入(DI):实现IoC的一种方式、手段。

IoC容器:依赖注入的框架,用来映射依赖,管理对象的创建和生存周期。

二、依赖

 

依赖就是有联系,有地方使用它就是有依赖它,下面看一个简单的示例:

class Program
    {
        class BMW
        {
            public string Show()
            {
                return "宝马";
            }
        }
        class ChinesePeople
        {
            private BMW bmw = new BMW();
            public void Run()
            {
                Console.WriteLine($"今天开{bmw.Show()}上班");
            }
        }

        static void Main(string[] args)
        {
            ChinesePeople people = new ChinesePeople();
            BMW bmw = new BMW();
            people.Run();
            Console.Read();
        }
    }

上面中国人开着宝马去上班,客户端有使用中国人、宝马汽车两个对象,中国人中有使用对象宝马汽车,我们可以从中找到三个依赖关系:

客户端依赖对象ChinesePeople;

客户端依赖对象BMW;

ChinesePeople依赖对象BMW;

三、依赖倒置原则 

        过些日子来了新需求,中国人不仅要开宝马去上班,还要开奔驰去上班,如果按照上面直接依赖关系的方式去做,我们就需要修改ChinesePeople类,让它实现一个参数为宝马的重载方法Run()。显然这样不是好的设计,我们总不能每次新增一种汽车(即修改下层模块)都要去修改ChinesePeople类吧(相对于汽车为上层模块),太麻烦了。。。
先简单分析一下,耦合关系就是依赖关系,如果依赖关系很重,牵一发而动全身,将很难维护扩展,耦合关系越少,系统会越稳定,因此要较少依赖。
定义:
A.高层模块不应依赖于底层模块,两者应该依赖于抽象。
B.抽象不应该依赖于细节,细节应该依赖于抽象。

在这个图中,我们发现高层模块定义接口,将不直接依赖于下层模块,下层模块负责实现高层模块定义的接口,下面看一下示例:

class Program
    {
        interface ICar
        {
            string Show();
        }

        class BMW : ICar
        {
            public string Show()
            {
                return "宝马";
            }
        }

        class BenZ : ICar
        {
            public string Show()
            {
                return "奔驰";
            }
        }

        interface IPeople
        {
            void Run(ICar car);
        }

        class ChinesePeople : IPeople
        {
            public void Run(ICar car)
            {
                Console.WriteLine($"今天开{car.Show()}上班");
            }
        }

        static void Main(string[] args)
        {
            ICar bmw = new BMW();
            ICar benz = new BenZ();
            IPeople people = new ChinesePeople();
            people.Run(bmw);
            people.Run(benz);
            Console.Read();
        }
    }

分析:上面代码中,ChinesePeople类不再依赖于具体的汽车,而是依赖于汽车的抽象,这样使得不管换什么样的汽车品牌,中国人都是可以开着去上班的,而且不需要修改ChinesePeople类。想一下,这样是不是挺好的。我们可以得出:上层不再依赖细节,相比面向实现,面向接口较好,因为抽象相比细节要更稳定。 

四、控制反转

        上面示例中,我们实现了具体的人和具体的汽车的隔离,具体人只和汽车的接口有关。但是Program中Main方法里的具体对象写死了,控制权变小,当我要修改美国人开着福特去上班时,就不得不要去修改代码,那怎么把控制权转移呢?

下面看一个简单的示例(请先添加System.Configuration引用):

    interface ICar
    {
        string Show();
    }
    interface IPeople
    {
        void Run(ICar car);
    }
class BMW : ICar
    {
        public string Show()
        {
            return "宝马";
        }
    }

class ChinesePeople : IPeople
    {
        public void Run(ICar car)
        {
            Console.WriteLine($"今天开{car.Show()}上班");
        }
    }

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <appSettings>
        <add key="People" value="LinkTo.Test.ConsoleIoC.ChinesePeople,LinkTo.Test.ConsoleIoC"/>
        <add key="Car" value="LinkTo.Test.ConsoleIoC.BMW,LinkTo.Test.ConsoleIoC"/>
    </appSettings>
</configuration>

class Program
    {
        static void Main(string[] args)
        {
            #region 反射+配置文件实现Ioc
            string people = ConfigurationManager.AppSettings["People"];
            string car = ConfigurationManager.AppSettings["Car"];
            Assembly assemblyPeople = Assembly.Load(people.Split(',')[1]);
            Assembly assemblyCar = Assembly.Load(car.Split(',')[1]);
            Type typePeople = assemblyPeople.GetType(people.Split(',')[0]);
            Type typeCar = assemblyPeople.GetType(car.Split(',')[0]);
            IPeople ipeople = (IPeople)Activator.CreateInstance(typePeople);
            ICar icar = (ICar)Activator.CreateInstance(typeCar);
            ipeople.Run(icar);
            Console.Read();
            #endregion
        }
    }

    上面代码中,我们使用反射+配置文件的方式,将对象创建的控制权转移到了配置文件,这就是所谓的控制反转

    分析:控制反转是将对象创建的控制权交给了第三方,可以是IoC容器,它就相当于简单工厂。我们要什么对象,工厂就给我们什么对象,这样依赖关系就变了,它们(人和车)都依赖于IoC容器,通过IoC容器建立它们之间的依赖关系。(依赖对象不再直接通过new来获取)

 五、依赖注入

        上面说到的控制反转,我们了解到是将控制权转移,这是我们的目的。配置文件+反射是一种实现,而依赖注入则提供的是一种思想,或者说是实现IoC的手段。

依赖注入是将对象的创建和绑定转移到被依赖对象的外部来实现,一般使用哪些方法来实现呢?

1、构造函数注入

class ChinesePeopleConstructor
    {
        private readonly ICar _car;

        //依赖注入:构造函数注入
        public ChinesePeopleConstructor(ICar car)
        {
            _car = car;
        }

        public void Run()
        {
            Console.WriteLine($"今天开{_car.Show()}上班");
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            #region 依赖注入:构造函数注入
            ICar bmw = new BMW();
            ChinesePeopleConstructor people = new ChinesePeopleConstructor(bmw);
            people.Run();
            Console.Read();
            #endregion
        }
    }

2、属性注入

class ChinesePeopleProperty
    {
        //依赖注入:属性注入
        public ICar Car { get; set; }

        public void Run()
        {
            Console.WriteLine($"今天开{Car.Show()}上班");
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            #region 依赖注入:属性注入
            ICar bmw = new BMW();
            ChinesePeopleProperty people = new ChinesePeopleProperty
            {
                Car = bmw
            };
            people.Run();
            Console.Read();
            #endregion
        }
    }

3、接口注入

    interface IDependent
    {
        void SetDependent(ICar icar);
    }

class ChinesePeopleInterface : IDependent
    {
        private ICar _car;

        //依赖注入:接口注入
        public void SetDependent(ICar car)
        {
            _car = car;
        }

        public void Run()
        {
            Console.WriteLine($"今天开{_car.Show()}上班");
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            #region 依赖注入:接口注入
            ICar bmw = new BMW();
            ChinesePeopleInterface people = new ChinesePeopleInterface();
            people.SetDependent(bmw);
            people.Run();
            Console.Read();
            #endregion
        }
    }

六、IoC容器

    IoC容器是一个DI框架,主要功能有一下几点:

    A.动态创建、注入依赖对象;

    B.管理对象生命周期;

    C.映射依赖关系;

    常见的IoC容器:Spring.NET,Castle Windsor, Ninject,Autofac,Unity

参考自:  https://www.cnblogs.com/jdzhang/p/7104351.html

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

MarcoPro

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值