C#:反射以及Attribute在ORM中的應用

C#:反射以及Attribute在ORM中的應用時間:2010-02-12 20:49:40來源:網絡 作者:未知 點擊:1210次 
一、 反射
一、 反射

  什麼是反射?

  簡單點吧,反射就是在運行時動態獲取對象信息的方法,比如運行時知道對象有哪些屬性,方法,委託等等等等。

  反射有什麼用呢?

  反射不但讓你在運行是獲取對象的信息,還提供運行時動態調用對象方法以及動態設置、獲取屬性等的能力。

  反射在ORM中有什麼用呢?

  我這裏所討論的ORM實現是通過自定義Attribute的方式進行映射規則的描述的。但是我們並不知道具體哪個對象需要對應哪個表,並且這些對象是獨立於我們的ORM框架的,所以我們只能通過自定義Attribute來定義映射規則,然後通過反射來動態獲取這些映射規則。

  反射的實現:

  下面我們就以簡單的獲取對象的屬性值的方式來做討論,假設我們有類Person,其中有3個屬性Name、Age,Sex。我們通過反射的方法來動態獲取Person的對象的這三個屬性的值。

public class Person 

  private string _Name; 
  private int _Age; 
  private string _Sex; 
  public string Name 
  { 
    get { return this._Name; } 
    set { this._Name = value; } 
  } 
  public int Age 
  { 
    get { return this._Age; } 
    set { this._Age = value; } 
  } 
  public string Sex 
  { 
    get { return this._Sex; } 
    set { this._Sex = value; } 
  } 
}
        測試代碼如下:

static class Program 

  [STAThread] 
  static void Main() 
  { 
    Person person = new Person(); 
    person.Name = "snoopy"; 
    person.Age = 5; 
    person.Sex = "male"; 
    PropertyInfo[] infos = person.GetType().GetProperties(); 
    Console.WriteLine("打印屬性"); 
    foreach (PropertyInfo info in infos) 
    { 
      //獲取屬性並打印 
      Console.WriteLine(info.Name + ":" + info.GetValue(person, null)); 
    } 
    Console.WriteLine("設置Person.Name = Hellokitty"); 
    //設置屬性,設置Name屬性 
    foreach (PropertyInfo info in infos) 
    { 
      if (info.Name == "Name") 
      { 
        info.SetValue(person, "Hellokitty", null); 
      } 
    } 
    Console.WriteLine("打印屬性"); 
    foreach (PropertyInfo info in infos) 
    { 
      //獲取屬性並打印 
      Console.WriteLine(info.Name + ":" + info.GetValue(person, null)); 
    } 
    Console.Read(); 
  } 
}
        執行結果:

       

         上面演示了通過反射的方法來動態獲取和設置對象屬性的方法。但是這和ORM以及Attribute有什麼關係呢?這個是我們接下來的這個部分的內容。

  上面演示了通過反射的方法來動態獲取和設置對象屬性的方法。但是這和ORM以及Attribute有什麼關係呢?這個是我們接下來的這個部分的內容。

  二、Attribute的使用:

  Attribute中文翻譯雖然也號稱“屬性”,但是她和對象的屬性(Property)其實是完全不同的兩概念。她是在運行時對對象或者對象屬性、方法、委託等等進行描述的類,用於在運行時描述你的代碼或者在運行時影響你的程序的行爲。

  其實我們在c#的編程中經常看到Attribute,只不過我們沒有注意罷了。比如Main函數前的“[STAThread]”這個其實就是一個Attribute。全程爲[STAThreadAttribute]。另外指定類可序列化的[Serializable]等等。是不是都很熟悉啊?只不過平時估計沒有用到,所以沒有注意罷了。

  既然Attribute是類,那麼她的定義方法和類就沒有兩樣了,唯一的不同就是自定義Attribute類必須繼承於System.Attribute。

  下面我們來簡單定義一個描述數據庫字段信息的Attribute,在此類中我們採用更省略的方式,僅僅提供“字段名”,“字段類型”:

public class DataFieldAttribute : Attribute 

  private string _FieldName; 
  private string _FieldType; 
  public DataFieldAttribute(string fieldname, string fieldtype) 
  { 
    this._FieldName = fieldname; 
    this._FieldType = fieldtype; 
  } 
  public string FieldName 
  { 
    get { return this._FieldName; } 
    set { this._FieldName = value; } 
  } 
  public string FieldType 
  { 
    get { return this._FieldType; } 
    set { this._FieldType = value; } 
  } 
}
        好,我們有了自己的描述數據庫字段的Attribute,那麼我們現在將其應用到實際的類中。我們還是繼續上面的Person類,使用方法如下:

public class Person 

  private string _Name; 
  private int _Age; 
  private string _Sex; 
  [DataFieldAttribute("name", "nvarchar")] 
  public string Name 
  { 
    get { return this._Name; } 
    set { this._Name = value; } 
  } 
  [DataFieldAttribute("age", "int")] 
  public int Age 
  { 
    get { return this._Age; } 
    set { this._Age = value; } 
  } 
  [DataFieldAttribute("sex", "nvarchar")] 
  public string Sex 
  { 
    get { return this._Sex; } 
    set { this._Sex = value; } 
  } 
}
        通過自定義Attribute,我們定義了類屬性和數據庫字段的一一對應關係,我們對Person類的Name、Age、Sex屬性都加上了Attribute的描述,指定了他們對應的字段名以及類型,其中Person.Name對應於字段name,字段類型Nvarchar...。

  三、反射和Attribute的聯合使用。

  從上面的描述中,我們瞭解了反射,瞭解了Attribute,瞭解了ORM映射規則的定義。但是剛接觸的朋友估計還是迷惑,我們怎麼動態獲取這些映射規則呢?

  這就需要使用反射了:

  下面的例子,我們由於對Person中的Name,Age以及SEX都增加了DataFieldAttribute的描述,這其實就是增加了O(對象)/R(關係數據庫)的映射規則,下面我們就通過反射的方法來動態獲取此映射規則:

static class Program 

  [STAThread] 
  static void Main() 
  { 
    Person person = new Person(); 
    person.Name = "snoopy"; 
    person.Age = 5; 
    person.Sex = "male"; 
    PropertyInfo[] infos = person.GetType().GetProperties(); 
    object[] objDataFieldAttribute = null; 
    foreach (PropertyInfo info in infos) 
    { 
      objDataFieldAttribute = info.GetCustomAttributes(typeof(DataFieldAttribute), false); 
      if (objDataFieldAttribute != null) 
      { 
        Console.WriteLine(info.Name + "->數據庫字段:" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName); 
      } 
    } 
  } 
}
        測試結果:

  接下來的工作就是怎樣根據這種方法動態地從對象中獲取映射規則,動態構造Insert,Update,Delete等語句。

  四、本章總結

  本章中比較詳細地介紹了反射,自定義Attribute的概念和應用,並且介紹了怎樣在運行時動態獲取O/R Mapping的映射規則等。當然我這裏的代碼僅僅是舉例,而要真正實現一個ORM,我們還需要考慮的很多,比如:

  1、Person對應於哪張數據庫表?

  2、Person中的PK和FK(如果有的話)怎麼表示?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章