詳解C#特性和反射(二)

  使用反射(Reflection)使得程序在運行過程當中能夠動態的獲取對象或類型的類型信息,而後調用該類型的方法和構造函數,或訪問和修改該類型的字段和屬性;能夠經過晚期綁定技術動態的建立類型的實例;能夠獲取程序集中的全部類型信息;能夠在動態構建新類型;還能夠檢索元素所添加的特性;
  ※反射相關的類基本都位於命名空間System.Reflection中;
  ※動態構建新類型的類位於命名空間System.Reflection.Emit中;數組


  1、訪問或修改類型的實例、靜態字段:函數

public class MyClass
{
    public int myField;
    public static int myStaticField;
}

//使用方式:
//訪問或修改類型的實例字段myField
MyClass myObj = new MyClass() { myField = 1 }; //建立實例
Type myType = typeof(MyClass); //獲取類型,或myObj.GetType()
FieldInfo fieldInfo = myType.GetField("myField"); //獲取類型中指定的字段信息
Console.WriteLine((int)fieldInfo.GetValue(myObj)); //1,獲取實例字段的值
fieldInfo.SetValue(myObj, 2); //給實例字段賦值
//訪問或修改類型的靜態字段myStaticField
FieldInfo staticFieldInfo = myType.GetField("myStaticField"); //獲取類型中指定的字段信息
Console.WriteLine(staticFieldInfo.GetValue(null)); //0,獲取靜態字段的值
staticFieldInfo.SetValue(null, 2); //給靜態字段賦值

  ※與直接賦值相比,使用反射賦值用時約長75倍,使用如下代碼屢次測試:測試

public class MyClass
{
    public int myField;
}

class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        MyClass myObj = new MyClass() { myField = 1 };
        Type myType = typeof(MyClass);
        FieldInfo fieldInfo = myType.GetField("myField");

        stopwatch.Start();
        for (int i = 0; i < 10_000_000; i++)
        {
            fieldInfo.SetValue(myObj, 2);
        }
        stopwatch.Stop();
        Console.WriteLine($"使用反射賦值1千萬次耗時:{stopwatch.ElapsedMilliseconds}");

        stopwatch.Reset();
        stopwatch.Start();
        for (int i = 0; i < 10_000_000; i++)
        {
            myObj.myField = 2;
        }
        stopwatch.Stop();
        Console.WriteLine($"直接賦值1千萬次耗時:{stopwatch.ElapsedMilliseconds}");
        Console.Read();
    }
}

  2、訪問或修改類型的實例、靜態屬性:this

public class MyClass
{
    public int MyProperty { get; set; }
    public static int MyStaticProperty { get; set; }
}
//使用方式:
//訪問或修改類型的實例屬性MyProperty MyClass myObj = new MyClass() { MyProperty = 1 }; //建立實例 Type myType = typeof(MyClass); //獲取類型,或myObj.GetType() PropertyInfo propertyInfo = myType.GetProperty("MyProperty"); //獲取類型中指定的屬性信息 Console.WriteLine((int)propertyInfo.GetValue(myObj, null)); //1,獲取實例屬性的值 propertyInfo.SetValue(myObj, 2, null); //給實例屬性賦值 //訪問或修改類型的靜態屬性MyStaticProperty PropertyInfo staticPropertyInfo = myType.GetProperty("MyStaticProperty"); //獲取類型中指定的屬性信息 Console.WriteLine(staticPropertyInfo.GetValue(null, null)); //0,獲取靜態屬性的值 staticPropertyInfo.SetValue(null, 2); //給靜態屬性賦值

  ※在使用反射給屬性賦值時,若是該屬性不具備set訪問器,則會拋出異常ArgumentException;spa

  3、調用類型的方法:pwa

public class MyClass
{
  public void MyFunc(int num)
  {
    Console.WriteLine("MyFunc(int num) execute, the parameter is: " + num);
  }
  public static void MyStaticFunc(int num)
  {
      Console.WriteLine("MyStaticFunc(int num) execute, the parameter is: " + num);
  }
}
//使用方式:
//調用類型的實例方法MyFunc MyClass myObj = new MyClass(); //建立實例 Type myType = typeof(MyClass); //獲取類型,或myObj.GetType() MethodInfo methodInfo = myType.GetMethod("MyFunc"); //獲取類型中指定的方法信息 methodInfo.Invoke(myObj, new object[] { 10 }); //調用實例方法,並傳入參數,無參傳null //MyFunc(int num) execute, the parameter is: 10 //調用類型的實例方法MyStaticFunc MethodInfo staticMethodInfo = myType.GetMethod("MyStaticFunc"); //獲取類型中指定的方法信息 staticMethodInfo.Invoke(null, new object[] { 20 }); //調用靜態方法,並傳入參數,無參傳null //MyStaticFunc(int num) execute, the parameter is: 20

  4、調用類型的構造函數同時建立實例:code

public class MyClass
{
    public MyClass()
    {
        Console.WriteLine("MyClass() execute.");
    }
    public MyClass(int num)
    {
        Console.WriteLine("MyClass(int num) execute, the parameter is: " + num);
    }
}
//使用方式:
//調用無參的構造函數 Type myType = typeof(MyClass); //獲取類型,或myObj.GetType() ConstructorInfo constructorInfo = myType.GetConstructor(new Type[] { }); //獲取類型中指定的構造函數信息,傳入該構造函數的參數列表的類型數組,無參傳空數組 MyClass myObj = constructorInfo.Invoke(null) as MyClass; //經過調用構造函數建立實例,無參傳null //MyClass() execute. //調用帶參數的構造函數 constructorInfo = myType.GetConstructor(new Type[] { typeof(int) }); //獲取類型中指定的構造函數信息,傳入該構造函數的參數列表的類型數組 myObj = constructorInfo.Invoke(new object[] { 20 }) as MyClass; //經過調用構造函數建立實例,並傳入參數 //MyClass(int num) execute, the parameter is: 20

  ※也可使用Type類中的實例方法InvokeMember()來調用指定成員;對象

  5、使用反射查找特性:blog

  1.若是元素使用了特性,在沒有檢索並對其進行操做前該特性沒有任何價值,可使用反射在程序運行過程當中獲取元素添加的特性而後對其進行操做,使用特性基類Attribute中的靜態方法GetCustomAttributes(MemberInfo element)或命名空間System.Reflection中的擴展方法GetCustomAttributes(this MemberInfo element)來獲取類型或成員的全部特性信息:element

Attribute[] attributes = Attribute.GetCustomAttributes(typeof(MyClass));
//IEnumerable<Attribute> attributes = typeof(MyClass).GetCustomAttributes();
foreach (var item in attributes)
{
  if (item is MyselfAttribute)
  {
    MyselfAttribute attribute = item as MyselfAttribute;
    Console.WriteLine(attribute .ClassName + " " + attribute .Author); //MyClass Me
  }
}

  2.這兩個方法都有對應的重載方法,能夠傳入要檢索的指定特性的類型,這樣便可獲得元素中全部指定類型的特性信息:

Attribute[] attributes = Attribute.GetCustomAttributes(typeof(MyClass), typeof(MyselfAttribute));
//IEnumerable<Attribute> attributes = typeof(MyClass).GetCustomAttributes(typeof(MyselfAttribute));
foreach (var item in attributes)
{
  MyselfAttribute attribute = item as MyselfAttribute;
  Console.WriteLine(attribute.ClassName + " " + attribute.Author); //MyClass Me
}

  ※若是未找到任何特性或指定類型的特性,這些方法會返回一個空數組;

  3.也可使用基類Attribute中的靜態方法GetCustomAttribute(MemberInfo element, Type attributeType)或命名空間System.Reflection中的擴展方法GetCustomAttribute(this MemberInfo element, Type attributeType)來獲取類型或成員的指定特性信息;
  ※若是未找到指定類型的特性,會返回null;
  ※在檢索的元素中存在多個相同的指定類型的特性時,會拋出異常Reflection.AmbiguousMatchException;

 

  類型信息、晚期綁定、動態建立類型等會在下一篇中介紹。

 


 

若是您以爲閱讀本文對您有幫助,請點一下「推薦」按鈕,您的承認是我寫做的最大動力!

做者:Minotauros
出處:https://www.cnblogs.com/minotauros/

本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。

相關文章
相關標籤/搜索