如何利用反射完成想要的功能,比如得到一個未知類的屬性。
屬性定義:它提供靈活的機制來讀取、編寫或計算某個私有字段的值。 可以像使用公共數據成員一樣使用屬性,但實際上它們是稱作“訪問器”的特殊方法。 這使得可以輕松訪問數據,此外還有助於提高方法的安全性和靈活性。屬性通常可以分為常規屬性和自動屬性。兩者之間還是有一點區別的,最開始編程對着兩個全無概念。
常規屬性
常規屬性以前做Winform的時候經常使用,現在開始使用EF,基本上都是使用自動屬性,看下常規屬性的完成構成:
1.私有字段,一般設置為私有,通過屬性來賦值保證起安全性:

1 private string _age;
2.get訪問器,負責讀取數據,其中可以進行自己的邏輯判斷和數據驗證,以return或者throw結束:

1 get 2 { 3 //年齡返回值判斷 4 return _age> 0 ? _age: 0; 5 }
3.set訪問器,負責給屬性賦值,類似於一個返回類型為void的方法,可以包含邏輯處理,例如可以根據默認的值通過計算后返回結果。
自動屬性
上面簡單的說了一下常規屬性,當屬性訪問器中不需要其他邏輯時,可以使用自動屬性,不過需要注意一點的就是聲明自動屬性時,編譯器將創建一個私有的匿名后備字段,該字段只能通過屬性的 get 和 set 訪問器進行訪問。

public int Id { get; set; }
自動屬性沒有太多可以可以說的東西,簡單的對比一下常規屬性和自動屬性之間的區別吧:
1.自動實現的屬性必須同時聲明 get 和 set 訪問器。創建 readonly 自動實現屬性時,需要將set 訪問器設置為private 。
2.自動實現的屬性 (Property) 不允許具有屬性 (Attribute)。如果必須在屬性 (Property) 的后備字段上使用屬性 (Attribute),則應該只創建常規屬性 (Property)。
3.自動實現屬性get,和set中不能包含特殊的邏輯處理。與字段類似,但不同於字段。與字段不同,屬性不作為變量來分類,不能將屬性作為 ref參數或 out參數傳遞
屬性PropertyInfo的使用
上面大概簡單的說了一下屬性和自動屬性之間的區別,現在可以回歸到文中最開始的時候的那個問題:
1.案例1,如果兩個類中有大部分的字段相同,需要將其中一個類的字段賦值給另外一個類:
定義Person類:

1 public class Person { 2 public Person(int id,string name,string address) 3 { 4 this.Id = id; 5 this.Name = name; 6 this.Address = address; 7 } 8 public int Id { get; set; } 9 public string Name { get; set; } 10 public string Address { get; set; } 11 }
定義User類

public class User { public int Id { get; set; } public string Name { get; set; } public string Group { get; set; } }
轉換方法(當兩個類有很多字段都是一樣的話,你又不想一個一個去賦值,可以使用下面這個方法):

1 public static User ConvertObject(User user,Person person) 2 { 3 PropertyInfo[] userPro = user.GetType().GetProperties(); 4 PropertyInfo[] personPro = person.GetType().GetProperties(); 5 if (userPro.Length>0&&personPro.Length>0) 6 { 7 for (int i = 0; i < userPro.Length; i++) 8 { 9 for (int j = 0; j < personPro.Length; j++) 10 { 11 //判斷User的屬性是不是的Person中 12 if (userPro[i].Name == personPro[j].Name && userPro[i].PropertyType == personPro[j].PropertyType) 13 { 14 Object value=personPro[j].GetValue(person, null); 15 //將Person中屬性的值賦值給User userPro[i].SetValue(user,value , null); 16 } 17 } 18 } 19 } 20 return user; 21 }
方法的調用:

1 static void Main(string[] args) 2 { 3 Person person = new Person(1,"Jerry","北京"); 4 User user = new User(); 5 user.Id = 20; 6 user = ConvertObject(user, person); 7 Console.WriteLine("Id:" + user.Id + "Name:" + user.Name + "角色:" + user.Group); 8 System.Console.Read(); 9 }
2.SqlHelper中使用SqlDataReader.Read時也可以使用,如下代碼大家應該很常見:

1 List<Person> list = new List<Person>(); 2 SqlDataReader sdr = new SqlDataReader(); 3 while (sdr.Read()) 4 { 5 Person person = new Person(); 6 person.Name = sdr.GetString(0); 7 //....下面類似,當屬性有幾十個的時候就相當煩人了 8 list.Add(person); 9 }
其實完全可以換一種方式來實現上面的代碼:

1 public static List<T> ConvertData<T>(SqlDataReader sdr) 2 { 3 List<T> list = new List<T>(); 4 Type type = typeof(T); 5 PropertyInfo[] properties = type.GetProperties(); 6 while (sdr.Read()) 7 { 8 T model = Activator.CreateInstance<T>(); 9 for (int i = 0; i < properties.Length; i++) 10 { 11 for (int j = 0; j < sdr.FieldCount; j++) 12 { 13 //判斷屬性的名稱和字段的名稱是否相同 14 if (properties[i].Name == sdr.GetName(j)) 15 { 16 Object value =sdr[j]; 17 //將字段的值賦值給User中的屬性 18 properties[i].SetValue(model, value, null); 19 } 20 } 21 } 22 list.Add(model); 23 } 24 return list; 25 }
調用的時候就相當簡單:

List<User> list = new List<User>(); SqlDataReader sdr = cmd.ExecuteReader(); list = ConvertData<User>(sdr);
3.案例三,去年開始學習的MVC,MVC封裝的很好,表單傳值的時候在action自動綁定,類似於這樣:
public ActionResult FormTest(string name,int id,....)
表單如果只有兩個或者三個字段還行,如果有十幾個字段,直接讓人崩潰了,要么就是Request,效果都不是很好,同樣的稍微改變了接收的方式,首先來說一下的就是Html頁面傳值整個表單的話,用serialize()就行,結果就是Name=xx&Age=xx,博客園的人應該對這沒有什么問題,我就懶一點,后台直接用一個字典去模擬了:
1 Dictionary<string, object> dic = new Dictionary<string, object>(); 2 dic.Add("Id",100); 3 dic.Add("Name", "keso"); 4 dic.Add("Group", "程序員");
轉換字典方法:

1 public static T ConvertDic<T>(Dictionary<string, object> dic) 2 { 3 T model = Activator.CreateInstance<T>(); 4 PropertyInfo[] modelPro = model.GetType().GetProperties(); 5 if (modelPro.Length > 0 && dic.Count() > 0) 6 { 7 for (int i = 0; i < modelPro.Length; i++) 8 { 9 if (dic.ContainsKey(modelPro[i].Name)) 10 { 11 modelPro[i].SetValue(model, dic[modelPro[i].Name], null); 12 } 13 } 14 } 15 return model; 16 }
最后的調用:
User user = ConvertDic<User>(dic);