Autofac简明教程

时间 修改内容 修改人
2020-10-19 初版 黄金民

0. Autofac介绍

Autofac是.NET世界里现存的几种IOC框架其中之一,传说是速度最快的一个。Autofac和其他容器的不同之处是它和C#语言的结合非常紧密,在使用过程中对你的应用的侵入性几乎为零,更容易与第三方的组件集成。

Tomato与Autofac

Tomato.dll是3D能力平台提供的基于Autofac的接口做的封装,提供了自动注册等功能,更易于使用。

1. 普通使用方式

使用Register标签自动注册,直接resolve接口获得对象实例,注意Singleton=true或者false的区别

QFord Begin Add on 2020-12-28

https://docs.unity3d.com/cn/current/Manual/ManagedCodeStripping.html

QFord End

示例:

namespace ConsoleApp1
{
    interface IHelloWorld
    {
        void SayHello();
    }

    ///注意!!Singleton=true代表是单例,每次resolve接口都会返回相同的对象实例
    ///注意!!Singleton=false代表非单例,每次resolve接口都会返回不同的对象实例
    [Register(Singleton =false)]
    class TestHello : IHelloWorld
    {
        public void SayHello()
        {
            Console.WriteLine("{0}-{1}", this.GetHashCode(), "TestHello");
        }
    }
    class Program
    {

        static void Main(string[] args)
        {
            ///初始化,扫描Register属性,自动注册接口
            DependencyInjection.Init();

            var instance1 = DependencyInjection.Container.Resolve<IHelloWorld>();
            instance1.SayHello();

            var instance2 = DependencyInjection.Container.Resolve<IHelloWorld>();
            instance2.SayHello();
        }
    }
}

输出:

//Singleton=false时输出:
63208015-TestHello
32001227-TestHello

//Singleton=true时输出:
63208015-TestHello
63208015-TestHello

2.进阶使用方式

按照Key来注册,并按照key来Resolve接口
适合用来做不同端的业务逻辑实现的区分
示例:

namespace ConsoleApp1
{
    interface IHelloWorld
    {
        void SayHello();
    }
    ///注意!!指定了Key=“3D”
    [Register(As =typeof(IHelloWorld), Key ="3D")]
    class Hello3D : IHelloWorld
    {
        public void SayHello()
        {
            Console.WriteLine("{0}-{1}", this.GetHashCode(), "Hello3D");
        }
    }

    ///注意!!指定了Key=“VR”
    [Register(As = typeof(IHelloWorld), Key = "VR")]
    class HelloVR : IHelloWorld
    {
        public void SayHello()
        {
            Console.WriteLine("{0}-{1}", this.GetHashCode(), "HelloVR");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            DependencyInjection.Init();
            //按照Key【3D】来Resolve接口
            var instance3D = DependencyInjection.Container.ResolveKeyed<IHelloWorld>("3D");
            instance3D.SayHello();
            //按照Key【VR】来Resolve接口
            var instanceVR = DependencyInjection.Container.ResolveKeyed<IHelloWorld>("VR");
            instanceVR.SayHello();
            ///默认Resolve方式,依然取到的是最后注册类的实例
            var c = DependencyInjection.Container.Resolve<IHelloWorld>();
            c.SayHello();
        }
    }
}

输出:

32001227-Hello3D //DependencyInjection.Container.ResolveKeyed<IHelloWorld>("3D")
19575591-HelloVR //DependencyInjection.Container.ResolveKeyed<IHelloWorld>("VR")
41962596-HelloVR //DependencyInjection.Container.Resolve<IHelloWorld>()

3.运行时替换

在运行时,依然可以替换接口的实现,主要用到AutofacHelper.Update<T>这个方法
示例:

namespace ConsoleApp1
{
    ...
    class OverrideHello : IHelloWorld
    {
        public void SayHello()
        {
            Console.WriteLine("{0}-{1}", this.GetHashCode(), "OverrideHello");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            DependencyInjection.Init();

            var testHello = DependencyInjection.Container.Resolve<IHelloWorld>();
            testHello.SayHello();

            OverrideHello overrideInstance = new OverrideHello();
            AutofacHelper.Update<IHelloWorld>(overrideInstance);
            var d = DependencyInjection.Container.Resolve<IHelloWorld>();
            d.SayHello()
        }
    }
}

输出:

63208015-TestHello
32001227-OverrideHello

4.如何提前做初始化

有时候某些接口的实现,涉及较复杂的初始化操作,比如读取大量的文件,如果在使用时再初始化,会带来比较明显的卡顿,可以考虑使用autofac自带的IStartable接口,它会在DependencyInjection.Init()的过程中被调用
可以在这个接口中触发异步初始化的功能。

示例:

namespace ConsoleApp1
{
    ...
    [Register(Singleton = true)]
    class Start : IStartable
    {
        void IStartable.Start()
        {
            Console.WriteLine("IStartable.Start");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            DependencyInjection.Init();

            var testHello = DependencyInjection.Container.Resolve<IHelloWorld>();
            testHello.SayHello();
        }
    }
}

输出:

IStartable.Start
32001227-TestHello

4.参考文档

官方教程文档-https://autofaccn.readthedocs.io/zh/latest/

QFord Begin Add on 2020-12-28

官方英文教程: https://autofaccn.readthedocs.io/en/latest/getting-started/index.html
git地址 wiki:https://github.com/autofac/Autofac/wiki
依赖注入的常见方式 : https://www.c-sharpcorner.com/article/understanding-the-dependency-injection-using-constructor-property-and-method-in/

QFord End