React與Redux之陣列處理講解
參考網址: 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