C#中PropertyInfo屬性用法


如何利用反射完成想要的功能,比如得到一個未知類的屬性。

屬性定義:它提供靈活的機制來讀取、編寫或計算某個私有字段的值。 可以像使用公共數據成員一樣使用屬性,但實際上它們是稱作“訪問器”的特殊方法。 這使得可以輕松訪問數據,此外還有助於提高方法的安全性和靈活性。屬性通常可以分為常規屬性和自動屬性。兩者之間還是有一點區別的,最開始編程對着兩個全無概念。

 

常規屬性

 常規屬性以前做Winform的時候經常使用,現在開始使用EF,基本上都是使用自動屬性,看下常規屬性的完成構成:

1.私有字段,一般設置為私有,通過屬性來賦值保證起安全性:

1 private string _age;
View Code

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

1 get
2  {
3      //年齡返回值判斷
4      return _age> 0 ? _age: 0;
5  }
View Code

3.set訪問器,負責給屬性賦值,類似於一個返回類型為void的方法,可以包含邏輯處理,例如可以根據默認的值通過計算后返回結果。

自動屬性

上面簡單的說了一下常規屬性,當屬性訪問器中不需要其他邏輯時,可以使用自動屬性,不過需要注意一點的就是聲明自動屬性時,編譯器將創建一個私有的匿名后備字段,該字段只能通過屬性的 get 和 set 訪問器進行訪問。

public int Id { get; set; }
View Code

自動屬性沒有太多可以可以說的東西,簡單的對比一下常規屬性和自動屬性之間的區別吧:

        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    }
View Code

定義User類

public class User {
       public int Id { get; set; }
       public string Name { get; set; }
       public string Group { get; set; }
   }
View Code

轉換方法(當兩個類有很多字段都是一樣的話,你又不想一個一個去賦值,可以使用下面這個方法):

 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        } 
View Code

方法的調用:

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       }
View Code

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 }
View Code

其實完全可以換一種方式來實現上面的代碼:

 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      }
View Code

調用的時候就相當簡單:

List<User> list = new List<User>();
SqlDataReader sdr = cmd.ExecuteReader();
list = ConvertData<User>(sdr);
View Code

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       }
View Code

最后的調用:

User user = ConvertDic<User>(dic);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM