首页 > 其他 > 详细

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

时间:2014-02-27 11:41:36      阅读:515      评论:0      收藏:0      [点我收藏+]
除去直接对类进行访问的方式之外,目前已经有三种方式,可以读取一个未知类型的对象的属性或字段。第一种也就是最常见的反射了,实现起来较为简单,但是如果每次要访问同一个类型的大量对象,则性能很差。第二种是采用Delegate的方式,参见:《采用Delegate对一个对象进行遍历,http://blog.csdn.net/kmguo/article/details/17392185 这种方式也有缺点,就是无法读取一个非基本类型及(String)类型的属性或字段。示例:
public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Location Location { get; set; }
    } 


    public class Location 
    { 
        public int Row { get; set; } 
        public int Col { get; set; } 
    }
采用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对象为例.

using System;
using System.Linq.Expressions;
using System.Reflection;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            object student = new Student
            {
                Id = 1,
                Name = "zhang san",
                Location = new Location
                {
                    Row = 10,
                    Col = 20
                }
            };
           VisitProperties<Student>(student);
        }

        /// <summary>
        /// 对未知类型的对象的属性进行递归访问
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        static void VisitProperties<T>(object obj)
        {
            var type = obj.GetType();
            var paraExpression = Expression.Parameter(typeof(T), "object");
            foreach (var prop in type.GetProperties())
            {
                var propType = prop.PropertyType;
                //判断是否为基本类型或String
                //访问方式的表达式树为:obj =>obj.Property
                if (propType.IsPrimitive || propType == typeof (String))
                {
                    VisitProperty<T>(obj, prop, paraExpression, paraExpression);
                }
                    
                else
                {
                    //对于访问方式的表达式树为: obj=>obj.otherObj.Property。

                    Console.WriteLine("not primitive property: " + prop.Name);
                    var otherType = prop.PropertyType;
                    MemberExpression memberExpression = Expression.Property(paraExpression, prop);
                    //访问obj.otherObj里的所有公有属性
                    foreach (var otherProp in otherType.GetProperties())
                    {
                        VisitProperty<T>(obj, otherProp, memberExpression, paraExpression);
                    }
                }
                Console.WriteLine("--------------------------------");
            }
        }

        /// <summary>
        /// 执行表达式树为: obj=>obj.Property 或 obj=>obj.otherObj.Property的计算
        /// </summary>
        /// <param name="instanceExpression">最终访问属性的obj对象的表达式树的表示</param>
        /// <param name="parameterExpression">类型T的参数表达式树的表示</param>
        static void VisitProperty<T>(Object obj, PropertyInfo prop, Expression instanceExpression, ParameterExpression parameterExpression)
        {
            Console.WriteLine("property name: " + prop.Name);

            MemberExpression memExpression = Expression.Property(instanceExpression, prop);
            //实现类型转换,如将Id的int类型转为object类型,便于下面的通用性
            Expression objectExpression = Expression.Convert(memExpression, typeof(object));
            Expression<Func<T, object>> lambdaExpression = Expression.Lambda<Func<T, object>>(objectExpression, parameterExpression);
            //打印表达式树
            Console.WriteLine("expression tree: " + lambdaExpression);
            Func<T, object> func = lambdaExpression.Compile();
            Console.WriteLine("value: " + func((T)obj)); //打印出得到的属性值
        }
    }

}

执行结果:
bubuko.com,布布扣

采用表达式树(Expression Tree)对一个对象的属性进行“遍历”,布布扣,bubuko.com

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

原文:http://blog.csdn.net/kmguo/article/details/19975331

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!