天天看點

.NET實作一個簡單的IOC容器

目錄

  • 0.關于IOC
  • 1.主要細節
  • 2.具體示例
    • 2.0 設計思路
    • 2.1 實作IOCFac.cs
    • 2.2 建立測試類和特性類
    • 2.3 運作測試
  • 參考及示例代碼下載下傳

shanzm-2020年3月17日 20:06:01

相關概念類知識,可以參考:

.NET中的控制反轉及AutoFac的簡單說明

  • 使用反射程式集的方式擷取對象的類型
  • 通過反射的方式擷取指定類型的的所有公共屬性
  • 通過特性的方式篩選需要注入對象的類型
  • 遞歸的方式為屬性注入依賴對象
  • TODO:循環依賴、生命周期、執行個體作用域

  • 首要,用什麼存儲對象,即什麼是對象容器?Dictionary類型做容器
  • 其次,怎麼擷取對象的類型?反射程式集
  • 再次,怎麼篩選對象類型?使用特性
  • 最後,怎麼實作屬性注入?遞歸

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;
        }


    }
           

建立兩個特性類:

// 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($"老師:教學中……");
    }
}
           

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();
}
           

運作結果:

老師:教學中……

學生:學習中……

  • 源碼下載下傳

作者:shanzm

[email protected]

歡迎交流,歡迎指教!

繼續閱讀