首页 > Asp.net开发 > 采用表达式树(Expression Tree)对一个对象的属性进行“遍历”

采用表达式树(Expression Tree)对一个对象的属性进行“遍历”

除去直接对类进行访问的方式之外,目前已经有三种方式,可以读取一个未知类型的对象的属性或字段。第一种也就是最常见的反射了,实现起来较为简单,但是如果每次要访问同一个类型的大量对象,则性能很差。第二种是采用Delegate的方式,参见:《采用Delegate对一个对象进行遍历,http://blog.csdn.net/kmguo/article/details/17392185 这种方式也有缺点,就是无法读取一个非基本类型及(String)类型的属性或字段。示例:

[csharp]

  1. public class Student  
  2.     {  
  3.         public int Id { getset; }  
  4.         public string Name { getset; }  
  5.         public Location Location { getset; }  
  6.     }   
  7.   
  8.   
  9.     public class Location   
  10.     {   
  11.         public int Row { getset; }   
  12.         public int Col { getset; }   
  13.     }  
采用Delegate的方式,只能获得Student的实例对象的Id及Name值(与String类的特殊性相关,因为调用它的ToString()方法就能直接得到我们想要的字符串),而不能得到Location里的Row及Col值(因为Location实例的ToString方法默认不会返回我们想要的Row及Col属性值)。
但是,可以采用Expression树的方式来得到,先建立表达式树,最后再将表达式树编译成Delegate来访问。
假设Student的一个实象对象为:student,在一般情况下,我们对其所有的公有属性,主要有以下的访问方式:
属性名称                            平时的访问方式                                Delegate的访问方式(Func<Student, object>)
Id                                       student.Id                                         s=>s.Id
Name                                student.Name                                   s=>s.Name
Location.Row                    student.Location.Row                      s=>s.Location.Row
Location.Col                      student.Location.Col                        s=>s.Location.Col
现在,我们可以采用Expression Tree的方式,“模拟”Delegate的访问方式,并最终“编译”成Delegate,即 Func<Tin,Tout>。为进一步说明采用Expression Tree的功能,现假设一个场景:我们要获得一个未知类型的对象的所有公有属性的值,如果属性不是基本类型或String,就进一步获得其内部的公有属性的值。以上面的Student对象为例.
[csharp]

  1. using System;  
  2. using System.Linq.Expressions;  
  3. using System.Reflection;  
  4. namespace ConsoleApplication1  
  5. {  
  6.     class Program  
  7.     {  
  8.         static void Main(string[] args)  
  9.         {  
  10.             object student = new Student  
  11.             {  
  12.                 Id = 1,  
  13.                 Name = "zhang san",  
  14.                 Location = new Location  
  15.                 {  
  16.                     Row = 10,  
  17.                     Col = 20  
  18.                 }  
  19.             };  
  20.            VisitProperties<Student>(student);  
  21.         }  
  22.   
  23.         /// <summary>  
  24.         /// 对未知类型的对象的属性进行递归访问  
  25.         /// </summary>  
  26.         /// <typeparam name="T"></typeparam>  
  27.         /// <param name="obj"></param>  
  28.         static void VisitProperties<T>(object obj)  
  29.         {  
  30.             var type = obj.GetType();  
  31.             var paraExpression = Expression.Parameter(typeof(T), "object");  
  32.             foreach (var prop in type.GetProperties())  
  33.             {  
  34.                 var propType = prop.PropertyType;  
  35.                 //判断是否为基本类型或String  
  36.                 //访问方式的表达式树为:obj =>obj.Property  
  37.                 if (propType.IsPrimitive || propType == typeof (String))  
  38.                 {  
  39.                     VisitProperty<T>(obj, prop, paraExpression, paraExpression);  
  40.                 }  
  41.                       
  42.                 else  
  43.                 {  
  44.                     //对于访问方式的表达式树为: obj=>obj.otherObj.Property。  
  45.   
  46.                     Console.WriteLine("not primitive property: " + prop.Name);  
  47.                     var otherType = prop.PropertyType;  
  48.                     MemberExpression memberExpression = Expression.Property(paraExpression, prop);  
  49.                     //访问obj.otherObj里的所有公有属性  
  50.                     foreach (var otherProp in otherType.GetProperties())  
  51.                     {  
  52.                         VisitProperty<T>(obj, otherProp, memberExpression, paraExpression);  
  53.                     }  
  54.                 }  
  55.                 Console.WriteLine("--------------------------------");  
  56.             }  
  57.         }  
  58.   
  59.         /// <summary>  
  60.         /// 执行表达式树为: obj=>obj.Property 或 obj=>obj.otherObj.Property的计算  
  61.         /// </summary>  
  62.         /// <param name="instanceExpression">最终访问属性的obj对象的表达式树的表示</param>  
  63.         /// <param name="parameterExpression">类型T的参数表达式树的表示</param>  
  64.         static void VisitProperty<T>(Object obj, PropertyInfo prop, Expression instanceExpression, ParameterExpression parameterExpression)  
  65.         {  
  66.             Console.WriteLine("property name: " + prop.Name);  
  67.   
  68.             MemberExpression memExpression = Expression.Property(instanceExpression, prop);  
  69.             //实现类型转换,如将Id的int类型转为object类型,便于下面的通用性  
  70.             Expression objectExpression = Expression.Convert(memExpression, typeof(object));  
  71.             Expression<Func<T, object>> lambdaExpression = Expression.Lambda<Func<T, object>>(objectExpression, parameterExpression);  
  72.             //打印表达式树  
  73.             Console.WriteLine("expression tree: " + lambdaExpression);  
  74.             Func<T, object> func = lambdaExpression.Compile();  
  75.             Console.WriteLine("value: " + func((T)obj)); //打印出得到的属性值  
  76.         }  
  77.     }  
  78.   
  79. }  

执行结果:


本文固定链接: http://www.devba.com/index.php/archives/5097.html | 开发吧

报歉!评论已关闭.