如何利用反射完成想要的功能,比如得到一个未知类的属性。
属性定义:它提供灵活的机制来读取、编写或计算某个私有字段的值。 可以像使用公共数据成员一样使用属性,但实际上它们是称作“访问器”的特殊方法。 这使得可以轻松访问数据,此外还有助于提高方法的安全性和灵活性。属性通常可以分为常规属性和自动属性。两者之间还是有一点区别的,最开始编程对着两个全无概念。
常规属性
常规属性以前做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);