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


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

運行結果:

老師:教學中……
學生:學習中……



參考及示例代碼下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM