【Unity|C#】基礎篇(12)——反射(Reflection)(核心類:Type、Assembly)


【學習資料】

  《C#圖解教程》(第24章)https://www.cnblogs.com/moonache/p/7687551.html
  電子書下載:https://pan.baidu.com/s/1mhOmBG0 

 

【內容】

  對以下文章的整合:

  知識點:

    • 用途
    • 命名空間
    • 主要類: System.Type  System.Reflection.Assembly 
    • System.Type類
      • 說明
      • 獲取給定類型的Type的3種方式
      • Type類的 常用屬性
      • Type類的 常用方法
    • 用反射生成對象
      • ConstructorInfo
      • Activator.CreateInstance
    • 使用Type反射舉例(創建對象、獲取並設置字段或屬性、調用方法)
    • Assembly類
      • 用途
      • Assembly常用方法
      • 使用舉例
    • 擴展知識
      • Assembly三種加載方式(LoadLoadFromLoadFile)的區別

 


 【文章整合筆記】

    • .NET的應用程序由幾個部分:程序集(Assembly)、模塊(Module)、類型(class)組成
    • 反射是.NET中的重要機制,通過反射,可以 在運行時,獲得程序或程序集中 每一個類型(包括類、結構、委托、接口和枚舉等)的 成員和成員的信息
    • 有了反射,即可對每一個類型了如指掌。另外我還可以直接創建對象,即使這個對象的類型在編譯時還不知道。 

        

  • 用途
    • Assembly           :定義和加載程序集,加載在程序集清單中列出模塊,以及從此程序集中查找類型並創建該類型的實例。 
    • Module               :了解包含 模塊 的程序集以及模塊中的類等,還可以獲取在模塊上定義的所有全局方法或其他特定的非全局方法。 
    • ConstructorInfo:了解 構造函數 的名稱、參數、訪問修飾符(如pulic 或private)和實現詳細信息(如abstract或virtual)等。 
    • ParameterInfo   :了解 參數 的名稱、數據類型、是輸入參數還是輸出參數,以及參數在方法簽名中的位置等。
    • EventInfo           :了解 事件 的名稱、事件處理程序數據類型、自定義屬性、聲明類型和反射類型等,添加或移除事件處理程序。 
    • FiedInfo             :了解 字段 的名稱、訪問修飾符(如public或private)和實現詳細信息(如static)等,並獲取或設置字段值。
    • PropertyInfo      :了解 屬性 的名稱、數據類型、聲明類型、反射類型和只讀或可寫狀態等,獲取或設置屬性值。 
    • MethodInfo        :了解 方法 的名稱、返回類型、參數、訪問修飾符(如pulic 或private)和實現詳細信息(如abstract或virtual)等。

 

  •  用到的命名空間
    •  System.Reflection 
    •  System.Type 
    •  System.Reflection.Assembly 

 

  • 用到的主要類
    •  System.Type 類                // 通過這個類可以訪問任何給定數據類型的信息。 
    •  System.Reflection.Assembly // 它可以用於訪問給定程序集的信息,或者把這個程序集加載到程序中。 

 

  • System.Type類
    • System.Type 類對於反射起着核心的作用
    • 但它是一個抽象的基類,Type有與每種數據類型對應的派生類,我們使用這個派生類的對象的方法、字段、屬性來查找有關該類型的所有信息
    • 程序中用到的每一個類型,CLR都會創建一個包含這個類型信息的Type類型的對象
    • 程序中用到的每一個類型,都會關聯到獨立的Type類型的對象
    • 不管創建的類型有多少個實例,只有一個Type對象會關聯到所有這些實例

        

 

    • 獲取給定類型Type引用的 3種方式:
      • typeof()
      • Type t = typeof(string);
      • object.GetType()
      • string s = "hello";
        Type t = s.GetType(); 
      • Type.GetType() :類型的完整名稱(包含命名空間名)
      • Type t = Type.GetType("System.String"); 
    • Type類的常用屬性  (以string為例)

        

    • Type類的常用方法
      • 注:只能獲取  public  的成員(字段、屬性、方法、事件、構造函數)

        

 

  • 通過反射生成對象
    • ConstructorInfo 生成對象
      • System.Type t = typeof(string);
        // 獲取參數為char[]的構造函數: string(char[]) System.Reflection.ConstructorInfo ci = t.GetConstructor(new Type[] { typeof(char[]) });
        // 等價於 object obj = new string( new char[] { 'h', 'e', 'l', 'l', 'o' } ) object obj = ci.Invoke(new object[] { new char[] { 'h', 'e', 'l', 'l', 'o' } });
    • Activator 生成對象
      • System.Type t = typeof(string);
        // 等價於 object obj = new string( new char[] { 'h', 'e', 'l', 'l', 'o' } ) object obj2 = Activator.CreateInstance(t, new char[] { 'h', 'e', 'l', 'l', 'o' });

 

  • 使用Type反射舉例(創建對象、獲取並設置字段或屬性、調用方法)
    • public class MyTest
      {
          // 字段
          public int value1  = 1;
          private int value2 = 2;
          // 屬性
          public string name1    { get; set; } = "hello";
          protected string name2 { get; set; } = "world";
          // 方法
          public void Show1()   { Debug.Log(name1 + value1); }
          internal void Show2() { Debug.Log(name2 + value2); }
      }
      
      void Start()
      {
          // 獲取 MyTest類 的 Type類型
          Type t = typeof(MyTest);
      
          // 使用Activator創建對象
          object obj = Activator.CreateInstance(t);
      
          // 獲取字段
          FieldInfo obj_value1 = t.GetField("value1");
          FieldInfo obj_value2 = t.GetField("value2");        // null,無法獲取 private 字段 // 獲取屬性
          PropertyInfo obj_name1 = t.GetProperty("name1");
          PropertyInfo obj_name2 = t.GetProperty("name2");    // null,無法獲取 protected 字段 // 獲取方法
          MethodInfo obj_Show1 = t.GetMethod("Show1");
          MethodInfo obj_Show2 = t.GetMethod("Show2");        // null,無法獲取 internal 字段 // 設置字段 SetValue
          obj_value1.SetValue(obj, 10);
          // 設置屬性 SetValue
          obj_name1.SetValue(obj, "heihei");
          // 調用方法 Invoke
          obj_Show1.Invoke(obj, null);
      }
    • 運行結果

         

 

  • Assembly類
    • 用途
      • 使用Assembly類可以降低程序集之間的耦合,有利於軟件結構的合理化
      • 獲得程序集的信息
      • 動態的加載程序集
      • 在程序集中查找類型信息
      • 創建該類型的實例
    • 常用的方法

        

    • 使用舉例
      • namespace MyNameSpace
        {
            public class LearnCS : MonoBehaviour
            {
                public class MyTest
                {
                    public class MySubTest { }
                }
        
                void Start()
                {
                    // 加載程序集,獲取Assembly實例
                    Assembly ass1 = Assembly.Load("Assembly-CSharp");
                    Assembly ass2 = Assembly.LoadFrom("C:/E/Projects/Demo/Library/ScriptAssemblies/Assembly-CSharp.dll");
                    Assembly ass3 = Assembly.LoadFile("C:/E/Projects/Demo/Library/ScriptAssemblies/Assembly-CSharp.dll");
        
                    // 獲取MyTest類型所在的程序集Assembly
                    Assembly ass = Assembly.GetAssembly(typeof(MyTest));
                    // 獲取當前運行的程序集Assembly
                    Assembly assembly = Assembly.GetExecutingAssembly();
        
                    // 獲取程序集名稱信息
                    string assembly_FullName = assembly.FullName;
                    AssemblyName assembly_Name = assembly.GetName();
                    // 獲取程序集路徑
                    string assembly_CodeBase = assembly.CodeBase;
                    string assembly_Location = assembly.Location;
        
                    // 獲取Type
                    Type[] types = assembly.GetTypes();
                    Type t = assembly.GetType("MyNameSpace.LearnCS+MyTest");         // 通過Type的FullName
        
                    // 創建實例
                    var obj = assembly.CreateInstance("MyNameSpace.LearnCS+MyTest"); // 通過Type的FullName
                }
            }
        }
    • 運行結果

        

 


 【擴展知識】

    • Load
      • 使用 程序集名 加載,Load("xxx")
      • 同時會 加載依賴 的其他程序集
      • 效率最高,優先使用這個方式
    • LoadFrom
      • 使用 路徑 加載,LoadFrom("x/xx/xxx.dll")
      • 可以通過URL加載("http://www.abc.com/test.dll"),會被下載到緩存文件中
      • 同時會 加載依賴 的其他程序集
      • 加載過的程序集,不會重新加載
      • 不能用於加載標識相同但路徑不同的程序集
    • LoadFile
      • 使用 路徑 加載,LoadFile("x/xx/xxx.dll")
      • 不會加載依賴 的程序集
      • 可以多次加載同一個程序集
      • 可以用來加載和檢查具有相同標識但位於不同路徑中的程序集,但不會加載程序的依賴項

 


免責聲明!

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



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