02.反射Reflection

位永光發表於2021-08-05

1. 基本瞭解

1.1 反射概述

文字說明

審查後設資料並收集關於它的型別資訊的能力稱為反射,其中後設資料(編譯以後的最基本資料單元)就是一大堆的表,當編譯程式集或者模組時,編譯器會建立一個類定義表,一個欄位定義表,和一個方法定義表等

反射提供了封裝程式集、模組和型別的物件(Type 型別),可以使用反射動態建立型別的例項,將型別繫結到現有物件,或從現有物件獲取型別並呼叫其方法或訪問其欄位和屬性。如果程式碼中使用了屬性,可以利用反射對它們進行訪問

實際上

反射是微軟封裝的一個幫助類庫:using System.Reflection;

1.2 反射用途

  • 使用Assembly定義和載入程式集,載入在程式集清單中列出模組,以及從此程式集中查詢型別並建立該型別的例項
  • 使用Module瞭解包含模組的程式集以及模組中的類等,還可以獲取在模組上定義的所有全域性方法或其他特定的非全域性方法
  • 使用ConstructorInfo瞭解建構函式的名稱、引數、訪問修飾符(如pulicprivate)和實現詳細資訊(如abstractvirtual)等;使用TypeGetConstructorsGetConstructor方法來呼叫特定的建構函式
  • 使用MethodInfo瞭解方法的名稱、返回型別、引數、訪問修飾符(如pulicprivate)和實現詳細資訊(如abstractvirtual)等;使用TypeGetMethodsGetMethod方法來呼叫特定的方法
  • 使用FiedInfo瞭解欄位的名稱、訪問修飾符(如publicprivate)和實現詳細資訊(如static)等,並獲取或設定欄位值。
  • 使用EventInfo瞭解事件的名稱、事件處理程式資料型別、自定義屬性、宣告型別和反射型別等,新增或移除事件處理程式。
  • 使用PropertyInfo瞭解屬性的名稱、資料型別、宣告型別、反射型別和只讀或可寫狀態等,獲取或設定屬性值
  • 使用ParameterInfo瞭解引數的名稱、資料型別、是輸入引數還是輸出引數,以及引數在方法簽名中的位置等

1.3 反射常用類

反射是一個程式集發現及執行的過程,通過反射能夠得到 .exe.dll 等程式集內部的資訊,使用反射能夠看到一個程式集內部的介面、類、方法、欄位、屬性、特性等資訊

型別 描述
Assembly 通過此類能夠載入操縱一個程式集,並獲取程式集內部資訊
FieldInfo 該類儲存給定的欄位資訊
MethodInfo 該類儲存給定的方法資訊
MemberInfo 該類是一個基類,定義了EventInfo,FieldInfo,MethodInfo,PropertyInfo的多個公用行為
Module 該類能夠使你能訪問多個程式集中的給定模組
ParameterInfo 該類儲存給定的引數資訊
PropertyInfo 該類儲存給定的屬性資訊

2. Assembly 程式集物件

2.1 物件簡介

官方文件

程式集包含模組、模組包含型別,而型別包含成員。 反射提供封裝程式集、模組和型別的物件。 可以使用反射動態地建立型別的例項,將型別繫結到現有物件,或從現有物件中獲取型別

其它文件

System.Reflection.Assembly:表示一個程式集

程式集是程式碼進行編譯是的一個邏輯單元,把相關的程式碼和型別進行組合,然後生成PE檔案(例如可執行檔案.exe和類庫檔案.dll

由於程式集在編譯後並不一定會生成單個檔案,而可能會生成多個物理檔案,甚至可能會生成分佈在不同位置的多個物理檔案,所以程式集是一個邏輯單元,而不是一個物理單元;即程式集在邏輯上是一個編譯單元,但在物理儲存上可以有多種存在形式

對於靜態程式集可以生成單個或多個檔案,而動態程式集是存在於記憶體中的

在C#中程式集處處可見,因為任何基於.NET的程式碼在編譯時都至少存在一個程式集(所有.NET專案都會預設引用mscorlib程式集)

程式集包含了兩種檔案:可執行檔案(.exe檔案)和 類庫檔案(.dll檔案)

在VS開發環境中,一個解決方案可以包含多個專案,而每個專案就是一個程式集

2.2 應用程式結構

包含應用程式域(AppDomain),程式集(Assembly),模組(Module),型別(Type),成員(EventInfo、FieldInfo、MethodInfo、PropertyInfo) 幾個層次

2.3 靜態方法

常用靜態方法

方法 返回值型別 描述
Assembly.Load Assembly 載入相對路徑下指定名稱程式集
Assembly.LoadFile Assembly 根據全路徑獲取指定程式集
Assembly.LoadFrom Assembly 根據全路徑獲取指定程式集

2.4 例項方法,屬性

常用例項屬性

屬性 屬性值型別 描述
assembly.FullName string 獲取程式集的顯示名稱
assembly.Location string 獲取程式集的完整路徑(全名稱)
assembly.DefinedTypes IEnumerable 獲取定義在程式集中型別集合
assembly.Modules IEnumerable 獲取定義在程式集中模組集合

常用例項方法

方法 返回值 描述
assembly.GetTypes() Type[] 獲取程式集中定義的型別陣列
assembly.GetType() Type 獲取程式集中定義的型別
assembly.GetExportedTypes() Type[] 獲取程式集中定義的所有公共型別(類,介面,列舉等)
assembly.CreateInstance() object 根據傳入型別建立型別例項

2.5 示例:載入程式集

方式一:Loadc2 引用了 Helper,有引用關係

using System;
using System.Reflection;
using Helper;

namespace c2
{
    class Program
    {
        static void Main(string[] args)
        {
            // 相對路徑下載入指定名稱程式集檔案
            Assembly assembly = Assembly.Load("Helper");
        }
    }
}

示例二:LoadFilec2taskdao無引用關係

using System;
using System.Reflection;

namespace c2
{
    class Program
    {
        static void Main(string[] args)
        {
            // 根據全名稱(路徑+檔名.字尾)下載入指定名稱程式集檔案
            Assembly assembly = 
                Assembly.LoadFile(@"E:\SolutionZX\taskdao\bin\Debug\taskdao.dll");
        }
    }
}

示例三:LoadFromc2taskdao無引用關係

using System;
using System.Reflection;

namespace c2
{
    class Program
    {
        static void Main(string[] args)
        {
            // 根據全名稱(路徑+檔名.字尾)下載入指定名稱程式集檔案
            Assembly assembly = 
                Assembly.LoadFrom(@"E:\SolutionZX\taskdao\bin\Debug\taskdao.dll");
        }
    }
}

示例四:根據型別建立型別例項,c2taskdao無引用關係

dynamic 型別為動態型別,使用時編譯器不會檢查(執行時檢查)

using System;
using System.Reflection;

namespace c2
{
    class Program
    {
        static void Main(string[] args)
        {
            
            // 根據全名稱(路徑+檔名.字尾)下載入指定名稱程式集檔案
            Assembly assembly = 
                Assembly.LoadFrom(@"E:\SolutionZX\taskdao\bin\Debug\taskdao.dll");

            // object _t = assembly.CreateInstance("task1dao.task1");
            // 報錯,object型別識別不出Show方法,因為C#是強型別語言
            // _t.Show();
            
            dynamic _t = assembly.CreateInstance("task1dao.task1");
            _t.Show();
        }
    }
}

2.6 獲取型別

獲取普通型別

Assembly assembly = typeof(Program).Assembly;
Type type = assembly.GetType("c2.UserInfo");

獲取泛型型別

Assembly assembly = typeof(Program).Assembly;
Type type = assembly.GetType("c2.UserInfo`1");	// UserInfo`1 英文狀態下數字1左邊符號,引數個數

3. Type 型別

在C#中可以理解為一個類對應一個Type物件

3.1 例項屬性,方法

例項屬性

屬性 屬性值型別 描述
type.Name string 獲取型別名稱(類名)
type.FullName string 獲取類全名(名稱空間+類名稱)
type.Namespace string 獲取類所在的名稱空間
type.Assembly string 獲取類所在程式集名稱
type.BaseType Type 獲取基類(父類)
type.IsSubclassOf(Type parent) bool type是否是parent的子類
type.IsInstanceOfType(object o) bool o是否是type類的物件
type.IsClass bool 獲取物件型別是否是類
type.IsInterface bool 獲取物件型別是否是介面
type.IsNotPublic bool 獲取物件型別是否公開
type.IsAbstract bool 獲取物件型別是否是抽象的
type.IsSealed bool 獲取物件型別是否是密封的
type.IsArray bool 獲取物件型別是否是陣列
type.IsEnum bool 獲取物件型別是否是列舉

例項方法

方法 返回值型別 描述
type.GetMembers() MemberInfo[] 獲取型別中所有公共成員
type.GetMethods() MethodInfo[] 獲取所有公共方法(包含基類)
type.GetConstructors() ConstructorInfo[] 獲取型別中所有公共建構函式
type.GetFields() FieldInfo[] 獲取所有公共欄位
type.GetProperties() PropertyInfo[] 獲取所有公共屬性
type.GetInterfaces() Type[] 獲取所有公共介面
type.MakeGenericType(...) Type 設定泛型類,泛型引數型別
type.GetMember(...) MemberInfo[] 多個,獲取公共成員(不常用)
type.GetMethod(...) MethodInfo 單個,獲取公共方法
type.GetConstructor(...) ConstructorInfo 單個,獲取公共方法
type.GetField(...) FieldInfo 單個,獲取公共欄位
type.GetProperty(...) PropertyInfo 單個,獲取公共屬性
type.GetInterface(...) Type 單個,獲取公共介面
type.IsDefined(...) bool 獲取此型別是否繼承指定特性
type.GetCustomAttributes(...) object[] 獲取此型別指定特性陣列

3.2 操作示例一

public class Base
{

}
public interface Inta { }

public interface Intb { }

public class UserInfo<A> : Base, Inta, Intb
{
    #region 公共建構函式
    public UserInfo()
    {
        Console.WriteLine("無參構造方法...");
    }
    public UserInfo(int id)
    {
        Console.WriteLine("1個引數構造方法");
    }
    #endregion

    #region 私有建構函式
    private UserInfo(string name) { }
    #endregion

    #region 公共欄位
    public string code;
    #endregion

    #region 私有欄位
    private string msg;
    #endregion

    #region 公共屬性
    public int id { get; set; }
    #endregion

    #region 公共方法
    public void Print()
    {
        Console.WriteLine("無引數例項方法");
    }

    public void Show()
    {
        Console.WriteLine("無引數過載例項方法");
    }
    public void Show(int id)
    {
        Console.WriteLine("有引數過載例項方法-" + id.ToString());
    }
    #endregion

    #region 公共靜態方法
    public static void Statc() { }
    #endregion

    #region 私有方法
    private void GetM()
    {
        Console.WriteLine("無引數私有方法");
    }
    private void GetM(int i)
    {
        Console.WriteLine("有引數私有方法-" + id.ToString());
    }
    #endregion

    #region 公共泛型方法
    public void GenericC(A a)
    {
        Console.WriteLine("公共泛型無參方法:" + a.ToString());
    }
    public void GenericS<T>()
    {
        Console.WriteLine("公共泛型無參方法");
    }

    public void GenericsA<T>(A a, T t)
    {
        Console.WriteLine("公共泛型有參方法:" + t.ToString() + "\t" + a.ToString());
    }

    #endregion
}

通過類獲得對應的Type

Type type = typeof(UserInfo);

通過 Assembly 物件,通過類的fullname類獲得Type物件

Assembly assem = Assembly.LoadFrom(@"E:\SolutionRP\DMO\bin\Debug\DMO.dll");
Type type = assem.GetType("DMO.UserInfo");

綜合示例

Type type = typeof(UserInfo);
Console.WriteLine("型別名:" + type.Name);
Console.WriteLine("類全名:" + type.FullName);
Console.WriteLine("名稱空間名:" + type.Namespace);
Console.WriteLine("程式集名:" + type.Assembly);
Console.WriteLine("模組名:" + type.Module);
Console.WriteLine("基類名:" + type.BaseType);
Console.WriteLine("是否類:" + type.IsClass);

MethodInfo method = type.GetMethod("Show");//獲得例項的方法

Console.WriteLine("類的公共成員:");

MemberInfo[] memberInfos = type.GetMembers();//得到所有公共成員
foreach (var item in memberInfos)
{
    Console.WriteLine("成員型別:" + item.MemberType + "\t成員:" + item);
}

3.3 示例二:獲取公共方法

一:獲取所有公共成員

static void Main(string[] args)
{
    Type type = typeof(UserInfo);

    Console.Write("獲取所有公共成員:");
    MemberInfo[] members =  type.GetMembers();
    Console.WriteLine(members.Length);

    Console.Write("獲取所有公共方法(包含基類):");
    MethodInfo[] methods = type.GetMethods();
    Console.WriteLine(methods.Length);

    Console.Write("獲取所有公共建構函式:");
    ConstructorInfo[] constructors = type.GetConstructors();
    Console.WriteLine(constructors.Length);

    Console.Write("獲取所有公共欄位:");
    FieldInfo[] fields = type.GetFields();
    Console.WriteLine(fields.Length);

    Console.Write("獲取所有公共屬性:");
    PropertyInfo[] properties = type.GetProperties();
    Console.WriteLine(properties.Length);

    Console.Write("獲取所有公共介面:");
    Type[] interfaces = type.GetInterfaces();
    Console.WriteLine(interfaces.Length);
}

根據名稱獲取公共成員(不常用)

MemberInfo[] memberInfo1 = type.GetMember("code");
MemberInfo[] memberInfo2 = type.GetMember("Show");
Console.WriteLine(memberInfo1.Length);
Console.WriteLine(memberInfo2.Length);

根據名稱獲取公共方法

// 獲取公共方法(非過載方法)
MethodInfo methodInfo1 = type.GetMethod("Print");
Console.WriteLine(methodInfo1.Name);

// 獲取公共過載方法,根據引數順序,型別,個數獲取
// 1.呼叫有一個int型別引數的過載方法
MethodInfo methodInfo2 = type.GetMethod("Show", new Type[] { typeof(int) });
// 2.呼叫無引數過載方法(不可傳null)
MethodInfo methodInfo3 = type.GetMethod("Show", new Type[0]);
Console.WriteLine(methodInfo3.Name);

根據引數的型別,數量,順序返回指定構造方法

// 返回無參公共構造方法
ConstructorInfo constructor1 = type.GetConstructor(new Type[0]);

// 返回有一個int型別引數的公共構造方法
ConstructorInfo constructor2 = type.GetConstructor(new Type[] { typeof(int) });

獲取型別公共欄位

FieldInfo fieldInfo1 = type.GetField("code");
Console.WriteLine(fieldInfo1.Name);

獲取型別公共屬性

PropertyInfo propertyInfo1 = type.GetProperty("id");
Console.WriteLine(propertyInfo1.Name);

3.4 示例三:獲取靜態方法

3.5 示例四:獲取泛型方法

獲取泛型方法

Assembly assembly = typeof(Program).Assembly;

// 獲取有一個泛型引數的類
Type type = assembly.GetType("c2.UserInfo`1");

// 指定泛型引數型別
Type generictype = type.MakeGenericType(new Type[] { typeof(int) });

object oType = Activator.CreateInstance(generictype);

3.6 示例五:獲取特性

[CustomAttribute]
public class Studen
{
    public void Show()
    {

    }
}
public class CustomAttribute : Attribute
{

}
static void Main(string[] args)
{
    Type type = typeof(Studen);
    if(type.IsDefined(typeof(CustomAttribute), true))
    {
        object[] oAttrbute = type.GetCustomAttributes(typeof(CustomAttribute), true);
        Console.WriteLine(oAttrbute.Length);
    }
}

4. MethodInfo 方法

一個 MethodInfo 表示一個方法(公共,私有,靜態,構造)

4.1 例項屬性,方法

例項屬性

屬性 屬性值型別 描述
methodInfo.Name string 方法名稱
methodInfo.ReturnType Type 獲取方法返回值型別
methodInfo.IsConstructor bool 是否是構造方法
methodInfo.IsAbstract bool 是否為抽象方法
methodInfo.IsPrivate bool 是否為私有方法
methodInfo.IsPublic bool 是否為公共方法
methodInfo.IsStatic bool 是否為靜態方法
methodInfo.IsVirtual bool 是否為虛方法
methodInfo.IsGenericMethod bool 是否為泛型方法

例項方法

方法 返回值 描述
methodInfo.Invoke(...) object 呼叫非泛型方法
methodInfo.GetParameters() ParameterInfo[] 獲取方法引數陣列
methodInfo.IsDefined(...) bool 獲取此方法是否繼承指定特性
methodInfo.GetCustomAttributes(...) object[] 獲取此方法指定特性陣列

4.2 操作示例一

獲取呼叫非泛型非過載無引數方法,無引數方法第二個引數可傳null,但不推薦

Type type = typeof(UserInfo);
object oType = Activator.CreateInstance(type);

MethodInfo methodInfo = null;

methodInfo = type.GetMethod("Print");

methodInfo.Invoke(oType,new object[0]);
methodInfo.Invoke(oType, null);

獲取呼叫非泛型過載無引數方法,無引數方法第二個引數可傳null,但不推薦

Type type = typeof(UserInfo);
object oType = Activator.CreateInstance(type);

MethodInfo methodInfo = null;

methodInfo = type.GetMethod("Show",new Type[0]);
methodInfo.Invoke(oType,new object[0]);
methodInfo.Invoke(oType, null);

獲取呼叫非泛型過載有引數方法,多個引數用逗號隔開,引數型別,個數,順序必須相同

Type type = typeof(UserInfo);
object oType = Activator.CreateInstance(type);

MethodInfo methodInfo = null;

methodInfo = type.GetMethod("Show", new Type[] { typeof(int) });
methodInfo.Invoke(oType, new object[] { 1 });

4.3 操作示例二

獲取泛型方法與獲取普通方法一致,泛型引數按從左到右順序傳入,方法引數型別與泛型引數型別一致

呼叫公共泛型無參方法

// 獲取泛型方法
MethodInfo methodInfo = type.GetMethod("GenericS");
// 指定泛型方法引數
MethodInfo genericmethod = methodInfo.MakeGenericMethod(new Type[] { typeof(int) });

genericmethod.Invoke(oType, null);

呼叫公共泛型有參方法

MethodInfo methodInfo = type.GetMethod("GenericsA");
MethodInfo genericsmethod = 
    methodInfo.MakeGenericMethod(new Type[] { typeof(int), typeof(string) });
genericsmethod.Invoke(oType, new object[] { 1 });

呼叫公共泛型類的有參方法,泛型類中的泛型引數與泛型方法的泛型引數一致

static void Main(string[] args)
{
    Assembly assembly = typeof(Program).Assembly;
    Type type = assembly.GetType("c2.UserInfo`1");

    Type generictype = type.MakeGenericType(new Type[] { typeof(int) });

    object oType = Activator.CreateInstance(generictype);

    MethodInfo methodInfo = generictype.GetMethod("GenericC");
    methodInfo.Invoke(oType, new object[] { 1 });
}

呼叫公共泛型類的有參方法,泛型類中的泛型引數與泛型方法的泛型引數不一致

static void Main(string[] args)
{
    Assembly assembly = typeof(Program).Assembly;
    Type type = assembly.GetType("c2.UserInfo`1");

    Type generictype = type.MakeGenericType(new Type[] { typeof(int) });

    object oType = Activator.CreateInstance(generictype);

    MethodInfo methodInfo = generictype.GetMethod("GenericsA");
    MethodInfo genericsmethodinfo = 
        methodInfo.MakeGenericMethod(new Type[] { typeof(string) });
    genericsmethodinfo.Invoke(oType, new object[] { 2, "af" });
}

5. ConstructorInfo 建構函式

5.1 例項屬性,方法

例項方法

方法 返回值型別 描述
constructor.Invoke(...) object 執行建構函式
constructor.IsDefined(...) bool 獲取此建構函式是否繼承指定特性
constructor.GetCustomAttributes(...) object[] 獲取此建構函式指定特性陣列

5.2 操作例項一

public class User
{
    public User()
    {
        Console.WriteLine("無參建構函式");
    }
    public User(string n)
    {
        Console.WriteLine("有參建構函式:" + n);
    }
}

呼叫建構函式

static void Main(string[] args)
{
    Assembly assembly = typeof(Program).Assembly;
    Type type = assembly.GetType("c2.User");

    object oType = Activator.CreateInstance(type);


    ConstructorInfo constructor = type.GetConstructor(new Type[0]);
    constructor.Invoke(oType, null);

    ConstructorInfo constructor1 = type.GetConstructor(new Type[] { typeof(string) });
    constructor1.Invoke(oType, new object[] { "liai" });

    ParameterInfo[] parameters = constructor1.GetParameters();
    Console.WriteLine(parameters.Length);
}

6. PropertyInfo 屬性

6.1 例項屬性,方法

例項屬性

屬性 屬性值型別 描述
property.Name string 獲取屬性名稱
property.CanRead bool 獲取屬性是否可讀
property.CanWrite bool 獲取屬性是否可寫
property.PropertyType Type 獲取屬性型別

例項方法

方法 返回值型別 描述
property.SetValue(...) void 設定物件屬性
property.GetValue(...) object 獲取物件屬性值
property.IsDefined(...) bool 獲取此屬性是否繼承指定特性
property.GetCustomAttributes(...) object[] 獲取此屬性指定特性陣列

6.2 操作例項一

獲取公共屬性

// 獲取所有
PropertyInfo[] propertys = type.GetProperty();

// 獲取指定
PropertyInfo property = type.GetProperty("no");

獲取屬性,設定屬性值,獲取屬性值

class Program
{
    static void Main(string[] args)
    {
        Assembly assembly = typeof(Program).Assembly;
        Type type = assembly.GetType("c2.Order");

        object oType = Activator.CreateInstance(type);

        PropertyInfo property = type.GetProperty("no");

        property.SetValue(oType,1);

        var value = property.GetValue(oType);
        Console.WriteLine(value);
    }
}


public class Order
{
    public int no { get; set; }
}

7. FieldInfo 欄位

7.1 例項屬性,方法

例項屬性

屬性名 屬性值型別 描述
field.Name string 獲取欄位名稱
field.Is... bool 獲取欄位是否為...
field.FieldType Type 獲取欄位型別

例項方法

方法 返回值型別 描述
field.IsDefined(...) bool 獲取此欄位是否繼承指定特性
field.GetCustomAttributes(...) object[] 獲取此欄位指定特性陣列

7.2 操作例項一

獲取欄位

class Program
{
    static void Main(string[] args)
    {
        Assembly assembly = typeof(Program).Assembly;
        Type type = assembly.GetType("c2.Order");

        object oType = Activator.CreateInstance(type);

        FieldInfo field = type.GetField("name");
        
        FieldInfo[] fields = type.GetFields();
    }
}


public class Order
{
    public string name;
}

獲取值,設定值

class Program
{
    static void Main(string[] args)
    {
        Assembly assembly = typeof(Program).Assembly;
        Type type = assembly.GetType("c2.Order");

        object oType = Activator.CreateInstance(type);

        FieldInfo field = type.GetField("name");
        field.SetValue(oType, "libai");

        var value = field.GetValue(oType);
        Console.WriteLine(value);
    }
}


public class Order
{
    public string name;
}

8. 擴充套件補充

8.1 載入程式集

獲得當前【應用程式域】中的所有程式集

Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();

獲得當前物件所屬的類所在的程式集

Assembly assembly = this.GetType().Assembly;

Assembly.LoadFileAssembly.LoadFrom的差別

  • LoadFile 方法用來載入和檢查具有同樣標識但位於不同路徑中的程式集,但不會載入程式的依賴項
  • LoadFrom 不能用於載入標識同樣但路徑不同的程式集

建立例項物件

此方法的作用與 new 一個例項物件相同

Activator.CreateInstance(type)

8.2 Module 程式集模組

Assembly assembly = Assembly.Load("mscorlib");//載入程式集
Module module = assembly.GetModule("CommonLanguageRuntimeLibrary");//得到指定模組
Console.WriteLine("模組名:" + module.Name);
Type[] types = module.FindTypes(Module.FilterTypeName, "Assembly*");
foreach (var item in types)
{
    Console.WriteLine("類名:" + item.Name);//輸出型別名
}

Console.Read();

8.3 BindingFlags說明

列舉值 描述
BindingFlags.Instance 物件例項
BindingFlags.Static 靜態成員
BindingFlags.Public 指可在搜尋中包含公共成員
BindingFlags.NonPublic 指可在搜尋中包含非公共成員(即私有成員和受保護的成員)
BindingFlags.FlattenHierarchy 指可包含層次結構上的靜態成員
BindingFlags.IgnoreCase 表示忽略 name 的大小寫
BindingFlags.DeclaredOnly 僅搜尋 Type 上宣告的成員,而不搜尋被簡單繼承的成員
BindingFlags.CreateInstance 表示呼叫建構函式。忽略 name。對其他呼叫標誌無效

8.4 屬性應用:ORM

簡易實現

public Order Find(int id)
{
    string sql = "select id,name,createTime from order where id = " +id;

    Type type = typeof(Order);
    object oOrder = Activator.CreateInstance(type);

    using (SqlConnection connection = new SqlConnection("constr"))
    {
        SqlCommand cmd = new SqlCommand(sql,connection);
        connection.Open();
        SqlDataReader reader = cmd.ExecuteReader();
        if (reader.Read())
        {
            foreach (var prop in type.GetProperties())
            {
                prop.SetValue(oOrder,prop.Name);
            }
        }
    }

    return (Order)oOrder;
}
// DTD
public class Order
{
    public int no { get; set; }
    public string name { get; set; }
    public DateTime createTime { get; set; }
}

泛型版本

public T Find<T>(int id) where T : BaseEntity
{
    string sql = "select id,name,createTime from order where id = " + id;

    Type type = typeof(T);
    object oOrder = Activator.CreateInstance(type);

    using (SqlConnection connection = new SqlConnection("constr"))
    {
        SqlCommand cmd = new SqlCommand(sql, connection);
        connection.Open();
        SqlDataReader reader = cmd.ExecuteReader();
        if (reader.Read())
        {
            foreach (var prop in type.GetProperties())
            {
                prop.SetValue(oOrder, prop.Name);
            }
        }
    }

    return (T)oOrder;
}

public class BaseEntity { }
public class Order:BaseEntity
{
    public int no { get; set; }
    public string name { get; set; }
    public DateTime createTime { get; set; }
}

相關文章