shanzm-2020年3月17日 20:06:01
0.關於IOC
相關概念類知識,可以參考:
.NET中的控制反轉及AutoFac的簡單說明
1.主要細節
-
使用反射程序集的方式獲取對象的類型
-
通過反射的方式獲取指定類型的的所有公共屬性
-
通過特性的方式篩選需要注入對象的類型
-
遞歸的方式為屬性注入依賴對象
-
TODO:循環依賴、生命周期、實例作用域
2.具體示例
2.0 設計思路
-
首要,用什么存儲對象,即什么是對象容器?Dictionary類型做容器
-
其次,怎么獲取對象的類型?反射程序集
-
再次,怎么篩選對象類型?使用特性
-
最后,怎么實現屬性注入?遞歸
2.1 實現IOCFac.cs
public class IOCFactory
{
// IOC容器(創建的對象的容器)
// string key:對象類型名
// object value:對象實例
private Dictionary<string, object> iocDictionaries = new Dictionary<string, object>();
// IOC中對象類型的容器
// string key:類型名
// Type value:類型
private Dictionary<string, Type> iocTypeDictionaries = new Dictionary<string, Type>();
//加載程序集,將含有我們自定義的特性標簽的類的類型存儲到類型容器中
public void LoadAssmaly(string asmName)
{
Assembly assembly = Assembly.Load(asmName);
Type[] types = assembly.GetTypes();//注意這里獲取的是程序集中的所有定義的類型
// 篩選出含有IOcServiceAttribute特性標簽的類,存儲其type類型
foreach (Type type in types)
{
IOCServiceAttribute iOCService = type.GetCustomAttribute(typeof(IOCServiceAttribute)) as IOCServiceAttribute;//獲取類上的自定義的特性標簽
if (iOCService != null)//如果是IOCServiceAttribute標注類,則把其類型存入類型容器中
{
iocTypeDictionaries.Add(type.Name, type);//最終其中的數據:{[Student, MyIOC.ClassLib.Student],[Teacher, MyIOC.ClassLib.Teacher]}
}
}
}
// ioc容器對象創建
public object GetObject(string typeName)
{
//根據參數取出指定的type
Type type = iocTypeDictionaries[typeName];
//創建type類型的對象
object objectValue = Activator.CreateInstance(type);
//獲取type類型對象的所有屬性
PropertyInfo[] propertyInfos = type.GetProperties();
foreach (PropertyInfo propertyInfo in propertyInfos)
{
//獲取類中屬性上的自定義IOCInjectAttribute特性標簽
IOCInjectAttribute iOCInject = (IOCInjectAttribute)propertyInfo.GetCustomAttribute(typeof(IOCInjectAttribute));
//如果該屬性是含有IOCInjectAttribute類型的特性,則為其也創建一個指定的實例(即注入依賴對象)
if (iOCInject != null)
{
//為objectValue的propertyInfo屬性賦值
//這里使用了遞歸的方式創建一個指定類型的實例
propertyInfo.SetValue(objectValue, GetObject(propertyInfo.PropertyType.Name));
}
}
//將創建的對象存儲到容器中
iocDictionaries.Add(typeName, objectValue);
return objectValue;
}
}
2.2 創建測試類和特性類
新建兩個特性類:
// IOC容器類特性
// 標記了IOCServiceAttribute特性的類,被注冊到容器
[AttributeUsage(AttributeTargets.Class)]//表示該自定義的屬性只能用於類之上
public class IOCServiceAttribute : Attribute
{
public IOCServiceAttribute()
{
}
}
// IOC依賴注入特性
// 標明IOCInjectAttribute特性的屬性,被注入
[AttributeUsage(AttributeTargets.Property)]//表示該自定義的屬性只能用於類之上
public class IOCInjectAttribute : Attribute
{
public IOCInjectAttribute()
{
}
}
新建兩個含有自定義特性的類
[IOCService]
public class Student
{
[IOCInject]
public Teacher Teacher { set; get; }
public void Study()
{
Teacher.Teach();
Console.WriteLine($"學生:學習中……");
}
}
[IOCService]
public class Teacher
{
//[IOCInject]
//public Student _Student { set; get; }
public void Teach()
{
Console.WriteLine($"老師:教學中……");
}
}
2.3 運行測試
static void Main(string[] args)
{
IOCFactory iOCFactory = new IOCFactory();
iOCFactory.LoadAssmaly("MyIOC");
Student student = (Student)iOCFactory.GetObject("Student");
//student.Teacher = teacher;//不需要在為屬性賦值,IOCFactory實現了屬性的注入
student.Study();
Console.ReadKey();
}
運行結果:
老師:教學中……
學生:學習中……