周波斯

导航

Autofac 学习简易教程随笔(一)

概念

        Autofac 是一款超赞的.NET IoC 容器 . 它管理类之间的依赖关系, 从而使 应用在规模及复杂性增长的情况下依然可以轻易地修改

        那么,什么是IoC(控制反转),以及IoC和DI(依赖注入),已经有大神对这个解释的非常清楚,感兴趣的可以看这个帖:https://www.iteye.com/blog/jinnianshilongnian-1413846

        本着多动原则,我这里直接进入step by step环节。本人也建议先按步骤做一遍简单的Autofac Demo项目,然后再看大神对IoC和DI介绍的帖子,会更容易理解。

实践

1、创建一个控制台项目,如下图:

2、引入autofac nuget包,如下图:

3、创建接口IVehicle(交通工具接口)、类Bus(巴士,实现IVehicle接口),代码如下:

    IVehicle.cs:

/// <summary>
    /// 交通工具接口
    /// </summary>
    public interface IVehicle
    {
        /// <summary>
        /// 去哪里
        /// </summary>
        /// <param name="targetAddress">目的地</param>
        void GoTo(string targetAddress);
    }
View Code

    Bus.cs:

/// <summary>
    /// 大巴
    /// </summary>
    public class Bus : IVehicle, IDisposable
    {
        private string _vehicleName { get; }

        public Bus()
        {
            _vehicleName = "大巴";
        }

        public void GoTo(string targetAddress)
        {
            Console.WriteLine($"乘 {_vehicleName} 去 {targetAddress}");
        }

        public void Dispose()
        {
            Console.WriteLine($"{nameof(Bus)} dispose");
        }
    }
View Code

4、创建接口IPassenger(乘客/旅客接口)、类Student(学生,实现IPassenger接口),代码如下:

    IPassenger:

/// <summary>
    /// 乘客/旅客接口
    /// </summary>
    public interface IPassenger
    {
        /// <summary>
        /// 乘坐交通工具去{targetAddr}(目的地)
        /// </summary>
        /// <param name="targetAddr">目的地</param>
        void ByVehicleTo(string targetAddr);
    }
View Code

   Student:

/// <summary>
    /// 学生旅客 实现了乘客/旅客接口
    /// </summary>
    public class Student : IPassenger
    {
        private readonly IVehicle _vehicle;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="vehicle">交通工具</param>
        public Student(IVehicle vehicle)
        {
            _vehicle = vehicle;
        }

        /// <summary>
        /// 乘坐交通工具去{targetAddr}(目的地)
        /// </summary>
        /// <param name="targetAddr"></param>
        public void ByVehicleTo(string targetAddr)
        {
            Console.WriteLine("学生旅客:");

            _vehicle.GoTo(targetAddr);
        }
    }
View Code

5、修改Program.cs的代码,如下:

class Program
    {
        private static IContainer Container { get; set; }

        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<Bus>().As<IVehicle>();
            //builder.RegisterType<Train>().As<IVehicle>();
            builder.RegisterType<Student>().As<IPassenger>();
            Container = builder.Build();

            Travel();

            Console.ReadLine();
        }


        public static void Travel()
        {
            using (var scope = Container.BeginLifetimeScope())
            {
                var passenger = scope.Resolve<IPassenger>();
                passenger.ByVehicleTo("Beijing");
            }
        }
    }
View Code

直接运行程序,得到结果如下:

 

代码解读

        回顾一下上面的代码,我们定义了两个接口:IPassenger(乘客/旅客接口)和IVehicle(交通工具接口),并且分别定义了Student(学生类)实现了IPassenger接口,以及Bus(巴士类)实现了IVehicle接口。

        但是,在Program.cs的代码中,我们并没用任何调用new直接生成Student或Bus对象的代码,下面我们看一下Main方法的代码注释,了解一下IoC容器简单的使用方法:

//以下代码是初始化容器并且注册程序中需要使用到的类型为组件

//实例化一个Autofac.ContainerBuilder对象
var builder = new ContainerBuilder();

//将Bus类型注册为组件,并暴露接口IVehicle作为服务。
builder.RegisterType<Bus>().As<IVehicle>();

//将Student类型注册为组件,并暴露接口IPassenger作为服务。
builder.RegisterType<Student>().As<IPassenger>();

//构建容器
Container = builder.Build();

  

  在看看Travel()方法中的代码:

public static void Travel(){
    //创建了一个生命周期范围(scope), 从中可以解析依赖项
    using (var scope = Container.BeginLifetimeScope())
    {
        //从生命周期范围(scope)中解析IPassenger,
        //Autofac发现IPassenger对应Student,因此开始创建Student
        //Autofac发现Student的构造方法需要一个IVehicle(这就是“构造方法注入”)
        //Autofac发现IVehicle对应Bus,因此开始创建新的Bus实例
        //Autofac使用新的Bus实例完成Student的创建
        //Autofac返回完整构建的 Student 给"Travel"方法使用
        var passenger = scope.Resolve<IPassenger>();

        //调用 passenger.ByVehicleTo("Beijing") 就是一个全新的 passenger.ByVehicleTo("Beijing") 因为这是在生命周期中解析出的
        passenger.ByVehicleTo("Beijing");

        //Autofac生命周期被释放. 任何从生命周期解析出的可释放对象也都被同时释放。
        //例如这里的Bus实现了IDisposable接口,在scope生命周期被释放的同时会调用Bus的Dispose。
    }
}

  

      如果后面需要增加一个交通工具,例如:Train(火车),同样实现接口IVehicle,代码如下:

public class Train : IVehicle
{
    public void GoTo(string targetAddress)
    {
        Console.WriteLine($"乘坐火车去 {targetAddress}");
    }
}
View Code

      然后只需修改Program.cs中Main方法内的IoC容器注册组件部分代码,如下:

static void Main(string[] args)
{
    var builder = new ContainerBuilder();
    //builder.RegisterType<Bus>().As<IVehicle>(); //这行代码注释掉
    builder.RegisterType<Train>().As<IVehicle>(); //加上这行代码
    builder.RegisterType<Student>().As<IPassenger>();
    Container = builder.Build();

    Travel();

    Console.ReadLine();
}

  然后运行程序,得出以下结果:

      Travel()方法里面的代码我们一点都没改,只是将IVehicle服务的对应组件注册类型修改为Train,结果就变成使用Train类的实例化运行了。这个就是IoC“控制反转”,也叫DI“依赖注入”。

 

源代码:https://github.com/LuckyDonkey/DotNet_Some_Samples/tree/master/IoC.DI.Autofac.Demos/IoC.DI.Autofac.FirstDemo

参考:https://autofaccn.readthedocs.io/zh/latest/getting-started/index.html

    

posted on 2020-08-31 23:44  周波斯  阅读(364)  评论(0编辑  收藏  举报