天天看點

c#反射和特性反射和特性

文章目錄

  • 反射和特性
    • 中繼資料和反射
    • Type類
    • Assembly類
    • 特性
      • Obsolete特性【棄用】
      • conditional特性
        • condation預設的環境配置
      • condation自定義參數
      • condation&#if
        • 引子
        • 總結
      • conditional使用多個辨別符【或邏輯】
        • 總結
      • condation實作'與'邏輯
        • 總結

反射和特性

中繼資料和反射

  • 程式是用來處理資料的,文本和特性都是資料,而我們程式本身(類的定義和BCL中的類)這些也是資料。(BCL-BasicClassLib基礎類庫)
  • 有關程式及其類型的資料被稱為中繼資料(metadata),它們儲存在程式的程式集中。
  • 程式在運作時,可以檢視其它程式集或其本身的中繼資料。一個運作的程式檢視本身的中繼資料或者其他程式集的中繼資料的行為叫做反射。【可以了解為反向映射】
  • 一個解決方案可以包含多個項目,而每個項目就是一個程式集。

    程式集基本上隻是一個DLL或EXE檔案。它包含IL代碼和描述該DLL或EXE中的代碼的類型資訊。它也可以包含很多其他内容,但是對于初學者來說,隻需将其視為DLL即可。

  • Type類位于System.Reflection命名空間下。
  • 如何使用Type類來反射資料,以及如何使用特性來給類型添加中繼資料。

Type類

  • 預定義類型(intlong和string等),BCL中的類型(ConsAe,lEnumerable等)和程式員自定義類型(MyClass,MyDel等)。每種類型都有自己的成員和特性。
  • BCL聲明了一個叫做Type的抽象類,它被設計用來包含類型的特性。使用這個類的對象能讓我們擷取程式使用的類型的資訊。
  • 由于Type是抽象類,是以不能利用它去執行個體化對象。關于Type的重要事項如下:對于程式中用到的每一個類型,CLR都會建立一個包含這個類型資訊的Type類型的對象。
  • 程式中用到的每一個類型都會關聯到獨立的Type類的對象。不管建立的類型有多少個示例,隻有一個Type對象會關聯到所有這些執行個體。
using System;
using System.Reflection;

namespace test07
{
    internal class Program
    {
        //反射
        public static void Main(string[] args)
        {
            //type
           //每個類對應一個type對象,抽象類是需要我們建立
           //兩種擷取方式
           //方式一:typeof(類名)
           Type t = typeof(MyClass);
           //方法二:通過執行個體的對象
           var myClass = new MyClass();
           var type = myClass.GetType();
           Console.WriteLine(type.Name);
           Console.WriteLine("========");
           //擷取MyClass的命名空間資訊
           Console.WriteLine(t.Namespace);
           //擷取MtClass的類名
           Console.WriteLine(t.Name);
           //擷取MyClass的程式集
           Console.WriteLine(t.Assembly); 
           //擷取MyClass[public修飾的]字段 将字段封裝為FileInfo
           FieldInfo[] fis = t.GetFields();
           foreach (FieldInfo fi in fis)
           {
               Console.WriteLine(fi.Name);
           }
           //擷取所有的屬性
            PropertyInfo[] pis = t.GetProperties();
            foreach (PropertyInfo pi in pis)
            {
                Console.WriteLine(pi.Name);
            }
            //擷取[public修飾的]方法
            MemberInfo[] mis = t.GetMethods();
            foreach (var mi in mis)
            {
                Console.WriteLine(mi.Name);
            }
        }
    }
}
           
c#反射和特性反射和特性

Assembly類

c#反射和特性反射和特性
c#反射和特性反射和特性

特性

  • 特性(attribute)是一種允許我們向程式的程式集增加中繼資料的語言結構。它是用于儲存程式結構資訊的某種特殊類型的類。
    • 将應用了特性的程式結構叫做目标。
    • 設計用來擷取和使用中繼資料的程式(對象浏覽器)叫做特性的消費者。
    • MET預定了很多特性,我們也可以聲明自定義特性。
      c#反射和特性反射和特性

Obsolete特性【棄用】

一個程式可能在其生命周期中經曆多次釋出,而且很可能延續多年。在程式生命周期的後半部分,程式員經常需要編寫類似功能的新方法替換老方法。處于多種原因,你可能不再使用哪些調用過時的舊方法的老代碼。而隻想用新編寫的代碼調用新方法。舊的方法不能删除,因為有些舊代碼也使用的舊方法,那麼如何提示程式員使用新代碼呢?可以使用Obsolete特性将程式結構标注為過期的,并且在代碼編譯時,顯示有用的警告資訊。

————————————————

版權聲明:本文為CSDN部落客「WhiteJunior」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。

原文連結:https://blog.csdn.net/lym940928/article/details/80550416

internal class Program
    {
    	//Obsolete特性用來表示一個方法被棄用了,并顯示有用的警告資訊
        //預設參數是false,表示不推薦使用,但并不會設定為錯誤
        //如果參數為true,就是設定為錯誤
        [Obsolete("這個方法已經棄用了,請使用最新的NewTest方法",true)]//特性:棄用
        static void Test()
        {
            Console.WriteLine("Test");
        }
        static void NewTest()
        {
            Console.WriteLine("NewTest");
        }
    
        public static void Main(string[] args)
        {
            //已經棄用了,調用會報錯
            //Test();
            NewTest();
        }
    }
           

conditional特性

condation預設的環境配置

  • Release/Debug
internal class Program
    {
        //參數定義了再debug環境下調用方法
        [Conditional("DEBUG")]
        static void ShowMessage(string str)
        {
            Console.WriteLine(str);
        }
        public static void Main(string[] args)
        {
            ShowMessage("Start of Main");
            
            ShowMessage("Running in Main");
            
            ShowMessage("end of Main");
        }
    }
           
c#反射和特性反射和特性

condation自定義參數

  • condation除了使用預設的環境配置,還可以通過宏定義來控制是否調用
  • 方式一:在程式的第一行定義編譯條件
#define UseFlag //需要寫到第一行
internal class Program
    {
        [Conditional("UseFlag")]
        static void Message()
        {
            Console.WriteLine("調用了宏定義參數的方法!");
        }
        public static void Main(string[] args)
        {
             Message();
        }
    }
           
c#反射和特性反射和特性
  • 方式二:在項目的properties裡面配置
    c#反射和特性反射和特性
  • 測試結果
    c#反射和特性反射和特性

condation&#if

引子

  • 測試一
#define Use
using System;
using System.Diagnostics;
[Conditional("Use")]
public static void Test1()
{
    Console.WriteLine("通過Conditional成功調用!");
}
           
public static void Test2()
{
  #if Use
      Console.WriteLine("通過#if成功調用!");
  #endif
}
           
public static void Main(string[] args)
{
    Test1();
    Test2();
}
           
  • 測試結果
    c#反射和特性反射和特性
  • 測試二
    • 在properties中配置
      c#反射和特性反射和特性
  • 測試結果
    c#反射和特性反射和特性

總結

  • 測試結果相同。但寫法并不等價!用Conditional屬性的方式,方法是否生效是取決于調用方,而用#if方式,Test方法是否生效是取決于方法定義所在的程式集。

conditional使用多個辨別符【或邏輯】

  • 隻定義了一個宏
    c#反射和特性反射和特性
[Conditional("Use"),Conditional("apply")]
public static void Test1()
{
   Console.WriteLine("通過Conditional成功調用!");
}
           
[Conditional("Use")][Conditional("apply")]
public static void Test3()
 {
     Console.WriteLine("通過Conditional成功調用!");
 }
           
c#反射和特性反射和特性

總結

  • 本質是‘或’邏輯

condation實作’與’邏輯

[Conditional("Use")]
public static void Test1()
{
    Console.WriteLine("通過Conditional成功調用!");
}

[Conditional("apply")]
public static void Test3()
{
    Test1();
}
public static void Main(string[] args)
{
    Test3();
}
           

總結

  • Conditional的好處:讓代碼更加具有閱讀性。
  • #if…#elif…#else…#endif這種邏輯性很強的代碼,建議采用#if的寫法,代碼可讀性更強。

繼續閱讀