1. 程式人生 > >C#反射的基本應用

C#反射的基本應用

映射 trim imp tco ray 模式 oar attribute stat

反射描述了在運行過程中檢查和處理程序元素的功能。反射可以完成以下任務:

  • 枚舉類型的成員;
  • 實例化新對象;
  • 執行對象的成員;
  • 查找類型的信息;
  • 查詢程序集的信息;
  • 檢查應用於某種類型的自定義特性;
  • 創建和編譯新程序集。

1、Type類

Type類是一個抽象的基類。只要實例化一個Type對象,實際上就是實例化了Type的一個派生類。獲取給定類型的Type引用三種方式:

  • 使用c#的typeof運算符。其參數是類型的名稱(不放在引號中);
  • 使用GetType()方法,所有的類都是繼承自Object類(值類型實際上也是如此),其具有該方法。
  • 調用Type類的靜態方法GetType():Type t=Type.GetType("System.Double")。

1.1、Type的屬性

Type的屬性可以分為三類。首先,許多屬性都可以獲取包含與類相關的各種名稱的字符串。

  • Name:數據類型名
  • FullName:數據類型的完全限定名(包括命名空間名)
  • Namespace:在其中定義數據類型的名稱空間名

其次,屬性能獲取Type對象的引用。

  • BaseType:該Type的直接基本類型
  • UnderlyingSystemType:該Type在.net運行庫中映射到類型(某些.net基類實際上映射到由IL識別的特定預定義類型)

  最後,許多布爾類型屬性表示這種類型是一個類,還是一個枚舉等。這些屬性包含:IsAbstract、IsArray、IsClass、IsEnum、IsInterface、IsPointer、IsPrimitive(一種預定義的基本數據類型)、IsPublic、IsSealed和IsValueType等。

1.2、Type的方法

  Type的大多數方法都用於獲取對應數據類型的成員信息:構造函數、屬性、方法和事件等。它的許多方法都具有想同的模式。

  • GetConstrucotr(), GetConstrucotrs():獲取ConstrucotrInfo對象類型;
  • GetEvent(), GetEvents():獲取EventInfo對象類型;
  • GetField(), GetFields():獲取FieldInfo對象類型;
  • GetMember(), GetMembers(), GetDefaultMembers():獲取MemberInfo對象類型;
  • GetMethod(), GetMethods():獲取MethodInfo對象類型;
  • GetProperty(), GetProperties(): 獲取PropertyInfo對象類型。

  GetMember()和GetMembers()方法返回數據類型的任何成員或所有成員的詳細信息,不管這些成員是構造函數、屬性或方法等。

2、Assembly類

  Assembly類允許訪問給定程序集的元素據,可以加載和執行程序集的方法等。使用Assembly實例之前需要加載對應的程序集到正在運行的進程中。使用靜態成員Assembly.Load()或Assembly.LoadFrom(),Load()方法的參數是程序集的名稱,運行庫會在哥哥位置上搜索該程序集,位置包括本地目錄和全局程序集緩存。LoadFrom()方法參數是完整的程序集路徑。

3、使用示例:

  相關源碼:https://files.cnblogs.com/files/pilgrim/MyReflection.rar

3.1、加載程序集,獲取對應的特性和創建對象:

 Console.WriteLine("*****************Reflection***********");
 Assembly assembly = Assembly.Load("DB.MySql");//獲取當前路徑下的dll,不需要後綴
 Module[] modules = assembly.GetModules();//獲取程序集中的所有模塊
 Type[] types = assembly.GetTypes();//獲取程序中所有的類型
 Attribute[] attributes= assembly.GetCustomAttributes().ToArray();//獲取程序中所有的自定義特性

 Type dbHlperType = assembly.GetType("DB.MySql.MySqlHlper");
 object oDBHlper = Activator.CreateInstance(dbHlperType);//創建對象(默認構造函數)
 DB.Interface.IDBHlper dBHlper = oDBHlper as DB.Interface.IDBHlper;
 dBHlper.Query();

  為使得程序更加靈活,可以將上面的代碼進行修改優化。使用應用程序配置文件+工廠方法,在配置文件中添加代碼:

  <add key="IDBHlper" value="DB.MySql,DB.MySql.MySqlHlper"/>。

  添加類讀取相關數據:

public class SimpleFactory
{
    /// <summary>
    /// 程序集名稱
    /// </summary>
    public static string DllName { get; private set; }
    /// <summary>
    /// 程序集中的某個類型名稱
    /// </summary>
    public static string TypeName { get; private set; }
    static SimpleFactory()
    {
        //從配置文件中讀取數據
        string[] iDBHlperConfig = ConfigurationManager.AppSettings["IDBHlper"].Split(,);
        DllName = iDBHlperConfig[0].Trim();
        TypeName = iDBHlperConfig[1].Trim();
    }

    /// <summary>
    /// 創建實例
    /// </summary>
    /// <returns></returns>
    public static DB.Interface.IDBHlper CreateInstance()
    {
        Assembly assembly = Assembly.Load(DllName);//加載程序集
        Type type = assembly.GetType(TypeName);//獲取對應的類型
        object dbHlper = Activator.CreateInstance(type);//創建實例
        return dbHlper as DB.Interface.IDBHlper;
    }
}

  在代碼調用時使用:

 //使用工廠方法創建實例
 DB.Interface.IDBHlper dBHlper2 = SimpleFactory.CreateInstance();
 dBHlper2.Query();
 Console.WriteLine();

3.2、使用程序集調用多構造函數、破壞單例、創建泛型類型等:

Assembly assembly = Assembly.Load("DB.SqlServer");//獲取當前路徑下的dll,不需要後綴
Type dbHlperType = assembly.GetType("DB.SqlServer.SqlServerHlper");
ConstructorInfo[] constructorInfos = dbHlperType.GetConstructors();//獲取所有的公共構造函數
//一個int類型參數的構造函數
object oDBHlper1 = Activator.CreateInstance(dbHlperType, new object[] { 520 });
//一個字符串類型參數的構造函數
object oDBHlper2 = Activator.CreateInstance(dbHlperType,new object[] { "一個字符串參數"});
//一個字符串類型和一個int類型參數的構造函數
object oDBHlper3 = Activator.CreateInstance(dbHlperType, new object[] { "一個字符串和一個int參數",520 });
//調用私有構造函數
object oDBHlper4 = Activator.CreateInstance(dbHlperType, true);
Console.WriteLine();
//獲取泛型類型,其有三個泛型參數
Type genericType = assembly.GetType("DB.SqlServer.GenericType`3");//`3是占位符,三個泛型參數
//將三個泛型參數類型的泛型創建為: float int string類型的類
Type type = genericType.MakeGenericType(typeof(float), typeof(int), typeof(string));
object oGeneric = Activator.CreateInstance(type);
Console.WriteLine(oGeneric.ToString());

3.3、使用反射調用實例方法、靜態方法、私有方法等:

Assembly assembly = Assembly.Load("DB.MySql");//獲取當前路徑下的dll,不需要後綴
Type type = assembly.GetType("DB.MySql.MySqlHlper");
object obj = Activator.CreateInstance(type);//創建對象(默認構造函數)
foreach (var item in type.GetMethods())
{
    Console.WriteLine(item.Name);
}
MethodInfo method = type.GetMethod("Query", new Type[] { } );//如果重載了,必須傳入參數類型
method.Invoke(obj, null);//誰調用,調用傳入的參數
//method.Invoke(null, null);//該方法只適用於靜態函數
MethodInfo method1 = type.GetMethod("Query", new Type[] { typeof(int) });
method1.Invoke(obj, new object[] { 520});//誰調用,調用傳入的參數
MethodInfo method2 = type.GetMethod("Query",new Type[] { typeof(string)});
method2.Invoke(obj, new object[] { "字符串" });//誰調用,調用傳入的參數

C#反射的基本應用