1. 程式人生 > 遊戲 >《凱娜:精神之橋》開發商:會繼續支援這款遊戲

《凱娜:精神之橋》開發商:會繼續支援這款遊戲

參考網址: https://www.cnblogs.com/atomy/p/12834804.html

一、為什麼使用Autofac?

Autofac是.NET領域最為流行的IoC框架之一,傳說是速度最快的一個。

1.1、效能

有人專門做了測試:

1.2、優點

1)與C#語言聯絡很緊密。C#裡的很多程式設計方式都可以為Autofac使用,例如可以使用Lambda表示式註冊元件。

2)較低的學習曲線。學習它非常的簡單,只要你理解了IoC和DI的概念以及在何時需要使用它們。

3)支援JSON/XML配置。

4)自動裝配。

5)與Asp.Net MVC整合。

6)微軟的Orchad開源程式使用的就是Autofac,可以看出它的方便和強大。

1.3、資源

官方網站:http://autofac.org/

GitHub網址:https://github.com/autofac/Autofac

學習資料:Autofac中文文件

二、資料準備

2.1、新建專案

IService下的介面類:

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

namespace LinkTo.Test.Autofac.IService
{
    /// <summary>
    /// 動物吠聲介面類
    /// </summary>
    public interface IAnimalBark
    {
        /// <summary>
        /// 吠叫
        /// </summary>
        void Bark();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinkTo.Test.Autofac.IService
{
    /// <summary>
    /// 動物睡眠介面類
    /// </summary>
    public interface IAnimalSleep
    {
        /// <summary>
        /// 睡眠
        /// </summary>
        void Sleep();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinkTo.Test.Autofac.IService
{
    /// <summary>
    /// 學校介面類
    /// </summary>
    public interface ISchool
    {
        /// <summary>
        /// 放學
        /// </summary>
        void LeaveSchool();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinkTo.Test.Autofac.IService
{
    /// <summary>
    /// 學生介面類
    /// </summary>
    public interface IStudent
    {
        /// <summary>
        /// 增加學生
        /// </summary>
        /// <param name="studentID">學生ID</param>
        /// <param name="studentName">學生姓名</param>
        void Add(string studentID, string studentName);
    }
}

Service下的介面實現類:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LinkTo.Test.Autofac.IService;

namespace LinkTo.Test.Autofac.Service
{
    /// <summary>
    /// 貓類
    /// </summary>
    public class Cat : IAnimalSleep
    {
        /// <summary>
        /// 睡眠
        /// </summary>
        public void Sleep()
        {
            Console.WriteLine("小貓咪睡著了zZ");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LinkTo.Test.Autofac.IService;

namespace LinkTo.Test.Autofac.Service
{
    /// <summary>
    /// 狗類
    /// </summary>
    public class Dog : IAnimalBark, IAnimalSleep
    {
        /// <summary>
        /// 吠叫
        /// </summary>
        public void Bark()
        {
            Console.WriteLine("汪汪汪");
        }

        /// <summary>
        /// 睡眠
        /// </summary>
        public void Sleep()
        {
            Console.WriteLine("小狗狗睡著了zZ");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LinkTo.Test.Autofac.IService;

namespace LinkTo.Test.Autofac.Service
{
    /// <summary>
    /// 學校類
    /// </summary>
    public class School : ISchool
    {
        /// <summary>
        /// IAnimalBark屬性
        /// </summary>
        public IAnimalBark AnimalBark { get; set; }

        /// <summary>
        /// 放學
        /// </summary>
        public void LeaveSchool()
        {
            AnimalBark.Bark();
            Console.WriteLine("你家的熊孩子放學了⊙o⊙");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LinkTo.Test.Autofac.IService;

namespace LinkTo.Test.Autofac.Service
{
    /// <summary>
    /// 學生類
    /// </summary>
    public class Student : IStudent
    {
        /// <summary>
        /// 無參建構函式
        /// </summary>
        public Student()
        { }

        /// <summary>
        /// 有參建構函式
        /// </summary>
        /// <param name="studentID">學生ID</param>
        /// <param name="studentName">學生姓名</param>
        public Student(string studentID, string studentName)
        {
            Add(studentID, studentName);
        }

        /// <summary>
        /// 增加學生
        /// </summary>
        /// <param name="studentID">學生ID</param>
        /// <param name="studentName">學生姓名</param>
        public void Add(string studentID, string studentName)
        {
            Console.WriteLine($"新增的學生是:{studentName}");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LinkTo.Test.Autofac.IService;

namespace LinkTo.Test.Autofac.Service
{
    /// <summary>
    /// 動物搖尾巴
    /// </summary>
    public class AnimalWagging
    {
        /// <summary>
        /// IAnimalBark屬性
        /// </summary>
        IAnimalBark animalBark;

        /// <summary>
        /// 有參建構函式
        /// </summary>
        /// <param name="bark">IAnimalBark變數</param>
        public AnimalWagging(IAnimalBark bark)
        {
            animalBark = bark;
        }

        /// <summary>
        /// 搖尾巴
        /// </summary>
        public virtual void Wagging()
        {
            animalBark.Bark();
            Console.WriteLine("搖尾巴");
        }

        /// <summary>
        /// 計數
        /// </summary>
        /// <returns></returns>
        public static int Count()
        {
            return 6;
        }

        /// <summary>
        /// 任務
        /// </summary>
        /// <param name="name">動物名稱</param>
        /// <returns></returns>
        public virtual async Task<string> WaggingAsync(string name)
        {
            var result = await Task.Run(() => Count());
            return $"{name}搖了{result}下尾巴";
        }
    }
}

2.2、Autofac安裝

Client專案右鍵->管理 NuGet 程式包->Autofac。

三、IoC-註冊

3.1、型別註冊

a)型別註冊:使用RegisterType進行註冊。

            //註冊Autofac元件
            ContainerBuilder builder = new ContainerBuilder();
            //註冊實現類Student,當我們請求IStudent介面的時候,返回的是類Student的物件。
            builder.RegisterType<Student>().As<IStudent>();
            //上面這句也可改成下面這句,這樣請求Student實現了的任何介面的時候,都會返回Student物件。
            //builder.RegisterType<Student>().AsImplementedInterfaces();
            IContainer container = builder.Build();
            //請求IStudent介面
            IStudent student = container.Resolve<IStudent>();
            student.Add("1001", "Hello");

b)型別註冊(別名):假如一個介面有多個實現類,可以在註冊時起別名。

            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Dog>().Named<IAnimalSleep>("Dog");
            builder.RegisterType<Cat>().Named<IAnimalSleep>("Cat");
            IContainer container = builder.Build();

            var dog = container.ResolveNamed<IAnimalSleep>("Dog");
            dog.Sleep();
            var cat = container.ResolveNamed<IAnimalSleep>("Cat");
            cat.Sleep();

c)型別註冊(列舉):假如一個介面有多個實現類,也可以使用列舉的方式註冊。

        public enum AnimalType
        {
            Dog,
            Cat
        }
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Dog>().Keyed<IAnimalSleep>(AnimalType.Dog);
            builder.RegisterType<Cat>().Keyed<IAnimalSleep>(AnimalType.Cat);
            IContainer container = builder.Build();

            var dog = container.ResolveKeyed<IAnimalSleep>(AnimalType.Dog);
            dog.Sleep();
            var cat = container.ResolveKeyed<IAnimalSleep>(AnimalType.Cat);
            cat.Sleep();

3.2、例項註冊

            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterInstance<IStudent>(new Student());
            IContainer container = builder.Build();

            IStudent student = container.Resolve<IStudent>();
            student.Add("1001", "Hello");

3.3、Lambda註冊

a)Lambda註冊

            ContainerBuilder builder = new ContainerBuilder();
            builder.Register(c => new Student()).As<IStudent>();
            IContainer container = builder.Build();

            IStudent student = container.Resolve<IStudent>();
            student.Add("1001", "Hello");

b)Lambda註冊(NamedParameter)

            ContainerBuilder builder = new ContainerBuilder();
            builder.Register<IAnimalSleep>((c, p) =>
                {
                    var type = p.Named<string>("type");
                    if (type == "Dog")
                    {
                        return new Dog();
                    }
                    else
                    {
                        return new Cat();
                    }
                }).As<IAnimalSleep>();
            IContainer container = builder.Build();

            var dog = container.Resolve<IAnimalSleep>(new NamedParameter("type", "Dog"));
            dog.Sleep();

3.4、程式集註冊

如果有很多介面及實現類,假如覺得這種一一註冊很麻煩的話,可以一次性全部註冊,當然也可以加篩選條件。

            ContainerBuilder builder = new ContainerBuilder();
            Assembly assembly = Assembly.Load("LinkTo.Test.Autofac.Service");   //實現類所在的程式集名稱
            builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();  //常用
            //builder.RegisterAssemblyTypes(assembly).Where(t=>t.Name.StartsWith("S")).AsImplementedInterfaces();  //帶篩選
            //builder.RegisterAssemblyTypes(assembly).Except<School>().AsImplementedInterfaces();  //帶篩選
            IContainer container = builder.Build();

            //單實現類的用法
            IStudent student = container.Resolve<IStudent>();
            student.Add("1001", "Hello");

            //多實現類的用法
            IEnumerable<IAnimalSleep> animals = container.Resolve<IEnumerable<IAnimalSleep>>();
            foreach (var item in animals)
            {
                item.Sleep();
            }

3.5、泛型註冊

            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterGeneric(typeof(List<>)).As(typeof(IList<>));
            IContainer container = builder.Build();

            IList<string> list = container.Resolve<IList<string>>();

3.6、預設註冊

            ContainerBuilder builder = new ContainerBuilder();
            //對於同一個介面,後面註冊的實現會覆蓋之前的實現。
            //如果不想覆蓋的話,可以用PreserveExistingDefaults,這樣會保留原來註冊的實現。
            builder.RegisterType<Dog>().As<IAnimalSleep>();
            builder.RegisterType<Cat>().As<IAnimalSleep>().PreserveExistingDefaults();  //指定為非預設值
            IContainer container = builder.Build();

            var dog = container.Resolve<IAnimalSleep>();
            dog.Sleep();

四、IoC-注入

4.1、建構函式注入

            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<AnimalWagging>();
            builder.RegisterType<Dog>().As<IAnimalBark>();
            IContainer container = builder.Build();

            AnimalWagging animal = container.Resolve<AnimalWagging>();
            animal.Wagging();

4.2、屬性注入

View Code

五、IoC-事件

Autofac在元件生命週期的不同階段,共對應了5個事件,執行順序如下所示:

1.OnRegistered->2.OnPreparing->3.OnActivating->4.OnActivated->5.OnRelease

View Code

六、IoC-生命週期

6.1、Per Dependency

Per Dependency:為預設的生命週期,也被稱為"transient"或"factory",其實就是每次請求都建立一個新的物件。

            ContainerBuilder builder = new ContainerBuilder();
            Assembly assembly = Assembly.Load("LinkTo.Test.Autofac.Service");                                                   //實現類所在的程式集名稱
            builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().PropertiesAutowired().InstancePerDependency();    //常用
            IContainer container = builder.Build();

            ISchool school1 = container.Resolve<ISchool>();
            ISchool school2 = container.Resolve<ISchool>();
            Console.WriteLine(school1.Equals(school2));

6.2、Single Instance

Single Instance:就是每次都用同一個物件。

            ContainerBuilder builder = new ContainerBuilder();
            Assembly assembly = Assembly.Load("LinkTo.Test.Autofac.Service");                                           //實現類所在的程式集名稱
            builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().PropertiesAutowired().SingleInstance();   //常用
            IContainer container = builder.Build();

            ISchool school1 = container.Resolve<ISchool>();
            ISchool school2 = container.Resolve<ISchool>();
            Console.WriteLine(ReferenceEquals(school1, school2));

6.3、Per Lifetime Scope

Per Lifetime Scope:同一個Lifetime生成的物件是同一個例項。

            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<School>().As<ISchool>().InstancePerLifetimeScope();
            IContainer container = builder.Build();
            ISchool school1 = container.Resolve<ISchool>();
            ISchool school2 = container.Resolve<ISchool>();
            Console.WriteLine(school1.Equals(school2));
            using (ILifetimeScope lifetime = container.BeginLifetimeScope())
            {
                ISchool school3 = lifetime.Resolve<ISchool>();
                ISchool school4 = lifetime.Resolve<ISchool>();
                Console.WriteLine(school3.Equals(school4));
                Console.WriteLine(school2.Equals(school3));
            }

七、IoC-通過配置檔案使用Autofac

7.1、元件安裝

Client專案右鍵->管理 NuGet 程式包->Autofac.Configuration及Microsoft.Extensions.Configuration.Xml。

7.2、配置檔案

新建一個AutofacConfigIoC.xml檔案,在其屬性的複製到輸出目錄項下選擇始終複製。

<?xml version="1.0" encoding="utf-8" ?>
<autofac defaultAssembly="LinkTo.Test.Autofac.IService">
  <!--無注入-->
  <components name="1001">
    <type>LinkTo.Test.Autofac.Service.Student, LinkTo.Test.Autofac.Service</type>
    <services name="0" type="LinkTo.Test.Autofac.IService.IStudent" />
    <injectProperties>true</injectProperties>
  </components>
  <components name="1002">
    <type>LinkTo.Test.Autofac.Service.Dog, LinkTo.Test.Autofac.Service</type>
    <services name="0" type="LinkTo.Test.Autofac.IService.IAnimalBark" />
    <injectProperties>true</injectProperties>
  </components>
  <!--建構函式注入-->
  <components name="2001">
    <type>LinkTo.Test.Autofac.Service.AnimalWagging, LinkTo.Test.Autofac.Service</type>
    <services name="0" type="LinkTo.Test.Autofac.Service.AnimalWagging, LinkTo.Test.Autofac.Service" />
    <injectProperties>true</injectProperties>
  </components>
  <!--屬性注入-->
  <components name="3001">
    <type>LinkTo.Test.Autofac.Service.School, LinkTo.Test.Autofac.Service</type>
    <services name="0" type="LinkTo.Test.Autofac.IService.ISchool" />
    <injectProperties>true</injectProperties>
  </components>
</autofac>

7.3、測試程式碼

            //載入配置
            ContainerBuilder builder = new ContainerBuilder();
            var config = new ConfigurationBuilder();
            config.AddXmlFile("AutofacConfigIoC.xml");
            var module = new ConfigurationModule(config.Build());
            builder.RegisterModule(module);
            IContainer container = builder.Build();
            //無注入測試
            IStudent student = container.Resolve<IStudent>();
            student.Add("1002", "World");
            //建構函式注入測試
            AnimalWagging animal = container.Resolve<AnimalWagging>();
            animal.Wagging();
            //屬性注入測試
            ISchool school = container.Resolve<ISchool>();
            school.LeaveSchool();

八、AOP

8.1、元件安裝

Client專案右鍵->管理 NuGet 程式包->Autofac.Extras.DynamicProxy。

8.2、攔截器

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Castle.DynamicProxy;

namespace LinkTo.Test.Autofac.Client
{
    /// <summary>
    /// 攔截器:需實現IInterceptor介面。
    /// </summary>
    public class CallLogger : IInterceptor
    {
        private readonly TextWriter _output;

        public CallLogger(TextWriter output)
        {
            _output = output;
        }

        /// <summary>
        /// 攔截方法:列印被攔截的方法--執行前的名稱、引數以及執行後的返回結果。
        /// </summary>
        /// <param name="invocation">被攔截方法的資訊</param>
        public void Intercept(IInvocation invocation)
        {
            //空白行
            _output.WriteLine();

            //在下一個攔截器或目標方法處理之前的處理
            _output.WriteLine($"呼叫方法:{invocation.Method.Name}");

            if (invocation.Arguments.Length > 0)
            {
                _output.WriteLine($"引數:{string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray())}");
            }

            //呼叫下一個攔截器(若存在),直到最終的目標方法(Target Method)。
            invocation.Proceed();

            //獲取被代理方法的返回型別
            var returnType = invocation.Method.ReturnType;

            //非同步方法
            if (IsAsyncMethod(invocation.Method))
            {
                //Task:返回值是固定型別
                if (returnType != null && returnType == typeof(Task))
                {
                    //定義一個非同步方法來等待目標方法返回的Task
                    async Task Continuation() => await (Task)invocation.ReturnValue;
                    //Continuation()中並沒有使用await,所以Continuation()就如同步方法一樣是阻塞的。
                    invocation.ReturnValue = Continuation();
                }
                //Task<T>:返回值是泛型型別
                else
                {
                    //獲取被代理方法的返回型別
                    var returnTypeT = invocation.Method.ReflectedType;
                    if (returnTypeT != null)
                    {
                        //獲取泛型引數集合,集合中的第一個元素等價於typeof(Class)。
                        var resultType = invocation.Method.ReturnType.GetGenericArguments()[0];
                        //利用反射獲得等待返回值的非同步方法
                        MethodInfo methodInfo = typeof(CallLogger).GetMethod("HandleAsync", BindingFlags.Public | BindingFlags.Instance);
                        //呼叫methodInfo類的MakeGenericMethod()方法,用獲得的型別T(<resultType>)來重新構造HandleAsync()方法。
                        var mi = methodInfo.MakeGenericMethod(resultType);
                        //Invoke:使用指定引數呼叫由當前例項表示的方法或建構函式。
                        invocation.ReturnValue = mi.Invoke(this, new[] { invocation.ReturnValue });
                    }
                }

                var type = invocation.Method.ReturnType;
                var resultProperty = type.GetProperty("Result");

                if (resultProperty != null)
                    _output.WriteLine($"方法結果:{resultProperty.GetValue(invocation.ReturnValue)}");
            }
            //同步方法
            else
            {
                if (returnType != null && returnType != typeof(void))
                    _output.WriteLine($"方法結果:{invocation.ReturnValue}");
            }
        }

        /// <summary>
        /// 判斷是否非同步方法
        /// </summary>
        public static bool IsAsyncMethod(MethodInfo method)
        {
            return 
                (
                    method.ReturnType == typeof(Task) || 
                    (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
                );
        }

        /// <summary>
        /// 構造等待返回值的非同步方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="task"></param>
        /// <returns></returns>
        public async Task<T> HandleAsync<T>(Task<T> task)
        {
            var t = await task;
            return t;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Castle.DynamicProxy;

namespace LinkTo.Test.Autofac.Client
{
    public class CallTester: IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("啥也不幹");
            invocation.Proceed();
            Console.WriteLine("也不幹啥");
        }
    }
}

8.3、測試程式碼

注意:對於以類方式的注入,Autofac Interceptor要求類的方法必須為virtual方法。如AnimalWagging類的Wagging()、WaggingAsync(string name)都加了virtual修飾符。

            ContainerBuilder builder = new ContainerBuilder();

            //註冊攔截器
            builder.Register(c => new CallLogger(Console.Out));
            builder.Register(c => new CallTester());

            //動態注入攔截器

            //這裡定義了兩個攔截器,注意它們的順序。
            builder.RegisterType<Student>().As<IStudent>().InterceptedBy(typeof(CallLogger), typeof(CallTester)).EnableInterfaceInterceptors();

            //這裡定義了一個攔截器
            builder.RegisterType<AnimalWagging>().InterceptedBy(typeof(CallLogger)).EnableClassInterceptors();
            builder.RegisterType<Dog>().As<IAnimalBark>();

            IContainer container = builder.Build();
            IStudent student = container.Resolve<IStudent>();
            student.Add("1003", "Kobe");

            AnimalWagging animal = container.Resolve<AnimalWagging>();
            animal.Wagging();

            Task<string> task = animal.WaggingAsync("哈士奇");
            Console.WriteLine($"{task.Result}");

IoC參考自:

https://www.xin3721.com/ArticlecSharp/c14013.html

https://www.cnblogs.com/GoogleGetZ/p/10218721.html

http://niuyi.github.io/blog/2012/04/06/autofac-by-unit-test/

https://www.cnblogs.com/kissdodog/p/3611799.html

AOP參考自:

https://www.cnblogs.com/stulzq/p/6880394.html

https://blog.csdn.net/weixin_38211198/article/details/105925821

https://blog.csdn.net/q932104843/article/details/97611912