Hello World
Spiga

这下没理由嫌Eval的性能差了吧?

2009-01-09 02:32 by 老赵, 16920 visits

Updated:提供思考题解答

好吧,你偏要说Eval性能差

写ASP.NET中使用Eval是再常见不过的手段了,好像任何一本ASP.NET书里都会描述如何把一个DataTable绑定到一个控件里去,并且通过Eval来取值的用法。不过在目前的DDD(Domain Driven Design)时代,我们操作的所操作的经常是领域模型对象。我们可以把任何一个实现了IEnumerable的对象作为绑定控件的数据源,并且在绑定控件中通过Eval来获取字段的值。如下:

protected void Page_Load(object sender, EventArgs e)
{
    List<Comment> comments = GetComments();
    this.rptComments.DataSource = comments;
    this.rptComments.DataBind();
}

<asp:Repeater runat="server" ID="rptComments">
    <ItemTemplate>
        Title: <%# Eval("Title") %><br />
        Conent: <%# Eval("Content") %>
    </ItemTemplate>
    <SeparatorTemplate>
        <hr />
    </SeparatorTemplate>
</asp:Repeater>

在这里,Eval对象就会通过反射来获取Title和Content属性的值。于是经常就有人会见到说:“反射,性能多差啊,我可不用!”。在这里我还是对这种追求细枝末节性能的做法持保留态度。当然,在上面的例子里我们的确可以换种写法:

<asp:Repeater runat="server" ID="rptComments">
    <ItemTemplate>
        Title: <%# (Container.DataItem as Comment).Title %><br />
        Conent: <%# (Container.DataItem as Comment).Content %>
    </ItemTemplate>
    <SeparatorTemplate>
        <hr />
    </SeparatorTemplate>
</asp:Repeater>

我们通过Container.DataItem来获取当前遍历过程中的数据对象,将其转换成Comment之后读取它的Title和Content属性。虽然表达式有些长,但似乎也是个不错的解决方法。性能嘛……肯定是有所提高了。

但是,在实际开发过程中,我们并不一定能够如此轻松的将某个特定类型的数据作为数据源,往往需要组合两种对象进行联合显示。例如,我们在显示评论列表时往往还会要显示发表用户的个人信息。由于C# 3.0中已经支持了匿名对象,所以我们可以这样做:

protected void Page_Load(object sender, EventArgs e)
{
    List<Comment> comments = GetComments();
    List<User> users = GetUsers();

    this.rptComments.DataSource = from c in comments
                                  from u in users
                                  where c.UserID == u.UserID
                                  order by c.CreateTime
                                  select new
                                  {
                                      Title = c.Title,
                                      Content = c.Content,
                                      NickName = u.NickName
                                  };
    this.rptComments.DataBind();
}

我们通过LINQ级联Comment和User数据集,可以轻松地构造出构造出作为数据源的匿名对象集合(有没有看出LINQ的美妙?)。上面的匿名对象将包含Title,Content和NickName几个公有属性,因此在页面中仍旧使用Eval来获取数据,不提。

不过我几乎可以肯定,又有人要叫了起来:“LINQ没有用!我们不用LINQ!Eval性能差!我们不用Eval!”。好吧,那么我免为其难地为他们用“最踏实”的技术重新实现一遍:

private Dictionary<int, User> m_users;
protected User GetUser(int userId)
{
    return this.m_users[userId];
}

protected void Page_Load(object sender, EventArgs e)
{
    List<Comment> comments = GetComments();
    List<User> users = GetUsers();

    this.m_users = new Dictionary<int, User>();
    foreach (User u in users)
    {
        this.m_users[u.UserID] = u;
    }

    this.rptComments.DataSource = comments;
    this.rptComments.DataBind();
}

<asp:Repeater runat="server" ID="rptComments">
    <ItemTemplate>
        Title: <%# (Container.DataItem as Comment).Title %><br />
        Conent: <%# (Container.DataItem as Comment).Content %><br />
        NickName: <%# this.GetUser((Container.DataItem as Comment).UserID).NickName %>
    </ItemTemplate>
    <SeparatorTemplate>
        <hr />
    </SeparatorTemplate>
</asp:Repeater>

兄弟们自己做判断吧。

嫌反射性能差?算有那么一点道理吧……

反射速度慢?我同意它是相对慢一些。

反射占CPU多?我同意他是相对多一点。

所以Eval不该使用?我不同意——怎能把孩子和脏水一起倒了?我们把反射访问属性的性能问题解决不就行了吗?

性能差的原因在于Eval使用了反射,解决这类问题的传统方法是使用Emit。但是.NET 3.5中现在已经有了Lambda Expression,我们动态构造一个Lambda Expression之后可以通过它的Compile方法来获得一个委托实例,至于Emit实现中的各种细节已经由.NET框架实现了——这一切还真没有太大难度了。

public class DynamicPropertyAccessor
{
    private Func<object, object> m_getter;

    public DynamicPropertyAccessor(Type type, string propertyName)
        : this(type.GetProperty(propertyName))
    { }

    public DynamicPropertyAccessor(PropertyInfo propertyInfo)
    {
        // target: (object)((({TargetType})instance).{Property})

        // preparing parameter, object type
        ParameterExpression instance = Expression.Parameter(
            typeof(object), "instance");

        // ({TargetType})instance
        Expression instanceCast = Expression.Convert(
            instance, propertyInfo.ReflectedType);

        // (({TargetType})instance).{Property}
        Expression propertyAccess = Expression.Property(
            instanceCast, propertyInfo);

        // (object)((({TargetType})instance).{Property})
        UnaryExpression castPropertyValue = Expression.Convert(
            propertyAccess, typeof(object));

        // Lambda expression
        Expression<Func<object, object>> lambda = 
            Expression.Lambda<Func<object, object>>(
                castPropertyValue, instance);

        this.m_getter = lambda.Compile();
    }

    public object GetValue(object o)
    {
        return this.m_getter(o);
    }
}

在DynamicPropertyAccessor中,我们为一个特定的属性构造一个形为o => object((Class)o).Property的Lambda表达式,它可以被Compile为一个Func<object, object>委托。最终我们可以通过为GetValue方法传入一个Class类型的对象来获取那个指定属性的值。

这个方法是不是比较眼熟?没错,我在《方法的直接调用,反射调用与……Lambda表达式调用》一文中也使用了类似的做法。

测试一下性能?

我们来比对一下属性的直接获取值,反射获取值与……Lambda表达式获取值三种方式之间的性能。

var t = new Temp { Value = null };

PropertyInfo propertyInfo = t.GetType().GetProperty("Value");
Stopwatch watch1 = new Stopwatch();
watch1.Start();
for (var i = 0; i < 1000000; i ++)
{
    var value = propertyInfo.GetValue(t, null);
}
watch1.Stop();
Console.WriteLine("Reflection: " + watch1.Elapsed);

DynamicPropertyAccessor property = new DynamicPropertyAccessor(t.GetType(), "Value");
Stopwatch watch2 = new Stopwatch();
watch2.Start();
for (var i = 0; i < 1000000; i++)
{
    var value = property.GetValue(t);
}
watch2.Stop();
Console.WriteLine("Lambda: " + watch2.Elapsed);

Stopwatch watch3 = new Stopwatch();
watch3.Start();
for (var i = 0; i < 1000000; i++)
{
    var value = t.Value;
}
watch3.Stop();
Console.WriteLine("Direct: " + watch3.Elapsed);

结果如下:

Reflection: 00:00:04.2695397
Lambda: 00:00:00.0445277
Direct: 00:00:00.0175414

使用了DynamicPropertyAccessor之后,性能虽比直接调用略慢,也已经有百倍的差距了。更值得一提的是,DynamicPropertyAccessor还支持对于匿名对象的属性的取值。这意味着,我们的Eval方法完全可以依托在DynamicPropertyAccessor之上。

离快速Eval只有一步之遥了

“一步之遥”?没错,那就是缓存。调用一个DynamicPropertyAccessor的GetValue方法很省时,可是构造一个DynamicPropertyAccessor对象却非常耗时。因此我们需要对DynamicPropertyAccessor对象进行缓存,如下:

public class DynamicPropertyAccessorCache
{
    private object m_mutex = new object();
    private Dictionary<Type, Dictionary<string, DynamicPropertyAccessor>> m_cache =
        new Dictionary<Type, Dictionary<string, DynamicPropertyAccessor>>();

    public DynamicPropertyAccessor GetAccessor(Type type, string propertyName)
    {
        DynamicPropertyAccessor accessor;
        Dictionary<string, DynamicPropertyAccessor> typeCache;

        if (this.m_cache.TryGetValue(type, out typeCache))
        {
            if (typeCache.TryGetValue(propertyName, out accessor))
            {
                return accessor;
            }
        }

        lock (m_mutex)
        {
            if (!this.m_cache.ContainsKey(type))
            {
                this.m_cache[type] = new Dictionary<string, DynamicPropertyAccessor>();
            }

            accessor = new DynamicPropertyAccessor(type, propertyName);
            this.m_cache[type][propertyName] = accessor;

            return accessor;
        }
    }
}

经过测试之后发现,由于每次都要从缓存中获取DynamicPropertyAccessor对象,调用性能有所下降,但是依旧比反射调用要快几十上百倍。

FastEval——还有人会拒绝吗?

FastEval方法,如果在之前的.NET版本中,我们可以将其定义在每个页面的共同基类里。不过既然我们在用.NET 3.5,我们可以使用Extension Method这种没有任何侵入的方式来实现:

public static class FastEvalExtensions
{
    private static DynamicPropertyAccessorCache s_cache = 
        new DynamicPropertyAccessorCache();

    public static object FastEval(this Control control, object o, string propertyName)
    {
        return s_cache.GetAccessor(o.GetType(), propertyName).GetValue(o);
    }

    public static object FastEval(this TemplateControl control, string propertyName)
    {
        return control.FastEval(control.Page.GetDataItem(), propertyName);
    }
}

我们在Control上的扩展,确保了每个页面中都可以直接通过一个对象和属性名获取一个值。而在TemplateControl上的扩展,则使得各类可以绑定控件或页面(Page,MasterPage,UserControl)都可以直接通过属性名来获取当前正在绑定的那个数据对象里的属性值。

现在,您还有什么理由拒绝FastEval?

其他

其实我们整篇文章都小看了Eval方法的作用。Eval方法的字符串参数名为“expression”,也就是表达式。事实上我们甚至可以使用“.”来分割字符串以获取一个对象深层次的属性,例如<%# Eval("Content.Length") %>。那么我们的FastEval可以做到这一点吗?当然可以——只不过这需要您自己来实现了。:)

最后再留一个问题供大家思考:现在DynamicPropertyAccessor只提供一个GetValue方法,那么您能否为其添加一个SetValue方法来设置这个属性呢?希望大家踊跃回复,稍后我将提供我的做法。

思考题解答

有一点大家应该知道,一个属性其实是由一对get/set方法组成(当然可能缺少其中一个)。而获取了一个属性的PropertyInfo对象之后,可以通过它的GetSetMethod方法来获取它的设置方法。接下来的工作,不就可以完全交给《方法的直接调用,反射调用与……Lambda表达式调用》一文里的DynamicMethodExecutor了吗?因此为DynamicPropertyAccessor添加一个SetValue方法也很简单:

public class DynamicPropertyAccessor
{
    ...
    private DynamicMethodExecutor m_dynamicSetter;

    ...

    public DynamicPropertyAccessor(PropertyInfo propertyInfo)
    {
        ...

        MethodInfo setMethod = propertyInfo.GetSetMethod();
        if (setMethod != null)
        {
            this.m_dynamicSetter = new DynamicMethodExecutor(setMethod);
        }
    }

    ...

    public void SetValue(object o, object value)
    {
        if (this.m_dynamicSetter == null)
        {
            throw new NotSupportedException("Cannot set the property.");
        }

        this.m_dynamicSetter.Execute(o, new object[] { value });
    }
}

在下面的评论中,Such Cloud已经想到了类似的做法,值得鼓励,同时多谢支持。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

128 条回复

  1. 大尾巴狼啊
    *.*.*.*
    链接

    大尾巴狼啊 2009-01-08 16:03:00

    经典哇!
    从前我用Eval咋就没想到呢。
    看来知识还是不够多呀。
    恩恩,回家看书去!

  2. 老赵
    admin
    链接

    老赵 2009-01-08 16:10:00

    --引用--------------------------------------------------
    live2map: Eval很好很强大。美中不足是script攻击的来源之一
    --------------------------------------------------------
    您一定没有看文章……

  3. live2map[未注册用户]
    *.*.*.*
    链接

    live2map[未注册用户] 2009-01-08 16:10:00

    Eval很好很强大。美中不足是script攻击的来源之一

  4. ITAres
    *.*.*.*
    链接

    ITAres 2009-01-08 16:14:00

    @live2map
    你以为是javascript啊?

  5. brightwang
    *.*.*.*
    链接

    brightwang 2009-01-08 16:17:00

    老赵最近精神可嘉,评劳模我投你一票。

  6. 幸运草
    *.*.*.*
    链接

    幸运草 2009-01-08 16:17:00

    很好,很强大,看到了差距

  7. Flymouse
    *.*.*.*
    链接

    Flymouse 2009-01-08 16:19:00

    @live2map
    呵呵,哪怕你多看几个字再回复都不会闹这笑话了。

  8. 周行天下
    *.*.*.*
    链接

    周行天下 2009-01-08 16:25:00

    年纪这么轻,久这么厉害。哎。

  9. brightwang
    *.*.*.*
    链接

    brightwang 2009-01-08 16:28:00

    很有现实意义的方法,平常因为eval的反射,绑定的时候都是进行转型。
    看了文章深觉自己在.net上还有很多东西要学。

  10. Astar
    *.*.*.*
    链接

    Astar 2009-01-08 16:46:00

    学习

  11. ThinkQ[未注册用户]
    *.*.*.*
    链接

    ThinkQ[未注册用户] 2009-01-08 16:49:00

    看来还有许多.net知识需要学习

  12. 凌军
    *.*.*.*
    链接

    凌军 2009-01-08 17:04:00

    根本没注意到Eval里面还有这么多学问...惭愧...

  13. Clingingboy
    *.*.*.*
    链接

    Clingingboy 2009-01-08 17:15:00

    要是没有反射,.net功能就大大缩水了.
    asp.net Mvc框架不也到处的反射.当然也要看应用的.

  14. 老赵
    admin
    链接

    老赵 2009-01-08 17:17:00

    @Clingingboy
    这话我同意

  15. andy.wu
    *.*.*.*
    链接

    andy.wu 2009-01-08 17:29:00

    强烈支持反射。

    为了FastEval,还得多耗我的精力。大多数情况下不值啊。

    但楼主的方法不错,值得学习,赞一个。

  16. 老赵
    admin
    链接

    老赵 2009-01-08 17:31:00

    @andy.wu
    哪里多耗你精力了?一个扩展,一劳永逸。平均到每次调用可以忽略不计。

  17. GUO Xingwang
    *.*.*.*
    链接

    GUO Xingwang 2009-01-08 17:43:00

    老赵擅长从小的地方发现问题并能找到解决方案,非常值得学习。
    现在看你的文章感觉很累,但是我知道必须要看,因为里面有很多好东西!
    下班以后好好品一下。

  18. 朝晖的.net
    *.*.*.*
    链接

    朝晖的.net 2009-01-08 17:57:00

    这篇挺不错的,受益匪浅。

    看着这个文章感觉偶要学习的东西还有好多啊。

    感觉老赵进入2009后迅速活跃起来了。

  19. joylee
    *.*.*.*
    链接

    joylee 2009-01-08 17:57:00

    我一般都是用Eval绑定的,可好多人都说使用服务器控件速度慢,
    1.真的可以整站不使用服务器控件吗?至少<form>要runat=server吧
    2.如果不用EVAL绑定数据那不就只有用string 拼接HTML了,还有其他方法吗??

    望老赵或其他高手赐教,不甚感激!!!!

  20. 阿不
    *.*.*.*
    链接

    阿不 2009-01-08 17:59:00

    老赵的表达式功力很深厚啊

  21. 老赵
    admin
    链接

    老赵 2009-01-08 18:04:00

    --引用--------------------------------------------------
    joylee: 我一般都是用Eval绑定的,可好多人都说使用服务器控件速度慢,
    1.真的可以整站不使用服务器控件吗?至少&lt;form&gt;要runat=server吧
    2.如果不用EVAL绑定数据那不就只有用string 拼接HTML了,还有其他方法吗??
    --------------------------------------------------------
    说慢的人,基本上是扯淡的。真正知道怎么开发高性能web应用程序的人不会在这种无所谓的小地方纠缠。

  22. Bēniaǒ
    *.*.*.*
    链接

    Bēniaǒ 2009-01-08 18:06:00

    很好很强大.

    老赵你这方法确实不错,以前用Eval通过反射整,后来在你那篇<<使用UserControl生成html>>文章写出来看过后,就是使用的后面那种绑定数据了.

  23. 老赵
    admin
    链接

    老赵 2009-01-08 18:06:00

    @要有好的心情
    都是内部类啊,不过我会比较一下看看的,呵呵。

  24. 老赵
    admin
    链接

    老赵 2009-01-08 18:07:00

    @Bēniaǒ
    类型转化+属性访问的也有好处,就是可以通过预编译aspx检查错误。

  25. 老赵
    admin
    链接

    老赵 2009-01-08 18:08:00

    --引用--------------------------------------------------
    朝晖的.net: 这篇挺不错的,受益匪浅。
    看着这个文章感觉偶要学习的东西还有好多啊。
    感觉老赵进入2009后迅速活跃起来了。
    --------------------------------------------------------
    老赵离江郎才尽永远只有3篇文章。

  26. 玉开
    *.*.*.*
    链接

    玉开 2009-01-08 18:13:00

    不错呀。

  27. Jerry Qian
    *.*.*.*
    链接

    Jerry Qian 2009-01-08 19:58:00

    老赵你这是level 几百的.你的文章我看得都挺有意思.可是一直是似懂非懂的.受措了.

  28. Such Cloud
    *.*.*.*
    链接

    Such Cloud 2009-01-08 20:10:00

    终于等到这篇文章了

  29. kkun
    *.*.*.*
    链接

    kkun 2009-01-08 20:23:00

    赵老师您好!
    又来问跑题问题了,文章刚看完,其中一段代码这样写到
    public DynamicPropertyAccessor(Type type, string propertyName)
    : this(type.GetProperty(propertyName))
    不太理解的说,在哪里有介绍这种写法的资料呀,

  30. 怪怪
    *.*.*.*
    链接

    怪怪 2009-01-08 20:25:00

    缓存的问题,可以用脑袋说的静态类型字典(借助泛型)解决。

    另外我不同意你说的细枝末节的性能。如Knuth所说,程序是编写一遍,运行很多次,哪怕一个时钟周期也是值得的。当然我并不贯彻这个做法,那是因为确实是能力有限,顾不了那么多了....

  31. kkun
    *.*.*.*
    链接

    kkun 2009-01-08 20:38:00

    现在超佩服赵老师的功力!~努力学习ing!

  32. bbb[未注册用户]
    *.*.*.*
    链接

    bbb[未注册用户] 2009-01-08 21:25:00

    怎能把孩子和脏水一起倒了?

  33. zbmwt[未注册用户]
    *.*.*.*
    链接

    zbmwt[未注册用户] 2009-01-08 22:39:00

    很有参考价值,不过有个问题。var t = new Temp { Value = null };
    这个测试的数据似乎太简单了,是否可以搞一个更复杂的进行测试?实际项目中,不可能只用这么简单的变量的。

  34. 天生俪姿
    *.*.*.*
    链接

    天生俪姿 2009-01-08 22:40:00

    虽说我也是没有太看完文章,不过很多的东西真的是还看不懂呵呵。挺不错的。学习中。。。
    继续支持老赵。

    老赵离江郎才尽永远只有3篇文章。
    这句当什么讲呢?老赵。

  35. Apple Yang
    *.*.*.*
    链接

    Apple Yang 2009-01-08 22:43:00

    好一本武林秘籍。

  36. 老赵
    admin
    链接

    老赵 2009-01-08 23:15:00

    --引用--------------------------------------------------
    怪怪: 缓存的问题,可以用脑袋说的静态类型字典(借助泛型)解决。

    另外我不同意你说的细枝末节的性能。如Knuth所说,程序是编写一遍,运行很多次,哪怕一个时钟周期也是值得的。当然我并不贯彻这个做法,那是因为确实是能力有限,顾不了那么多了....
    --------------------------------------------------------
    关于缓存使用静态字典,莫非就是我现在用的做法?我一直用这种方法的,好像也是最常用的做法。
    追求细致末节性能当然是可以的,但是不能为此抛弃其他的,比如优雅,易于编写等等。如果追求性能应该去优化瓶颈,当然如果属于不会影响编码,一次编写多次运行也是好的——就像我现在这样,呵呵。

  37. 老赵
    admin
    链接

    老赵 2009-01-08 23:16:00

    --引用--------------------------------------------------
    天生俪姿:
    老赵离江郎才尽永远只有3篇文章。
    这句当什么讲呢?老赵。
    --------------------------------------------------------
    如果停止思考或失去灵感,就只能写3篇文章。

  38. 老赵
    admin
    链接

    老赵 2009-01-08 23:19:00

    --引用--------------------------------------------------
    zbmwt: 很有参考价值,不过有个问题。var t = new Temp { Value = null };
    这个测试的数据似乎太简单了,是否可以搞一个更复杂的进行测试?实际项目中,不可能只用这么简单的变量的。
    --------------------------------------------------------
    再复杂不也是在访问属性吗?这种简单示例确保性能比较时完全是由访问属性的方式决定的,如果一个属性访问一次本身就要很长时间,那么测试时反而无法关注主要矛盾了。

  39. 老赵
    admin
    链接

    老赵 2009-01-08 23:19:00

    --引用--------------------------------------------------
    kkun: 赵老师您好!
    又来问跑题问题了,文章刚看完,其中一段代码这样写到
    public DynamicPropertyAccessor(Type type, string propertyName)
    : this(type.GetProperty(propertyName))
    不太理解的说,在哪里有介绍这种写法的资料呀,
    --------------------------------------------------------
    你不了解C#语法啊……自己看文档吧。

  40. ITAres
    *.*.*.*
    链接

    ITAres 2009-01-08 23:20:00

    有个问题想问老赵,希望老赵可以回答我:
    MethodInfo methodInfo = typeof(Program).GetMethod("Call");
    -----------我一直以为这一步的时候就进行了反射操作,看你的文章应该是没有的....

    methodInfo.Invoke(program, parameters);
    ------------你的意思是这一步的时候才进行了反射,是吗?

  41. 老赵
    admin
    链接

    老赵 2009-01-08 23:20:00

    --引用--------------------------------------------------
    bbb: 怎能把孩子和脏水一起倒了?
    --------------------------------------------------------
    因为Eval这个性能问题但是把优雅简单的编码方式也放弃了。

  42. 老赵
    admin
    链接

    老赵 2009-01-08 23:22:00

    --引用--------------------------------------------------
    ITAres: 有个问题想问老赵,希望老赵可以回答我:
    MethodInfo methodInfo = typeof(Program).GetMethod("Call");
    -----------我一直以为这一步的时候就进行了反射操作,看你的文章应该是没有的....

    methodInfo.Invoke(program, parameters);
    ------------你的意思是这一步的时候才进行了反射,是吗?
    --------------------------------------------------------
    GetMethod是反射,不过这种方法其实很省时,而且完全可以获取一次后反复调用无数次,就不考虑进去了。真正耗时的是Invoke操作。

  43. ITAres
    *.*.*.*
    链接

    ITAres 2009-01-08 23:25:00

    @Jeffrey Zhao
    老赵天才啊

  44. Such Cloud
    *.*.*.*
    链接

    Such Cloud 2009-01-09 00:24:00

    终于脑子转过弯了 把老赵的作业做出来 贴出来 大家看看有没有更好的方法
    public class DynamicPropertyAccessor
    {
    private Func<object, object> m_getter;
    private Action<Temp,object> m_setter;
    private Temp entity;

    public DynamicPropertyAccessor(Temp t, string propertyName)
    {
    this.entity = t;
    Type type = t.GetType();

    PropertyInfo propertyInfo = type.GetProperty(propertyName);

    // target: (object)((({TargetType})instance).{Property})

    // preparing parameter, object type
    ParameterExpression instance = Expression.Parameter(
    typeof(object), "instance");

    // ({TargetType})instance
    Expression instanceCast = Expression.Convert(
    instance, propertyInfo.ReflectedType);

    // (({TargetType})instance).{Property}
    Expression propertyAccess = Expression.Property(
    instanceCast, propertyInfo);

    // (object)((({TargetType})instance).{Property})
    UnaryExpression castPropertyValue = Expression.Convert(
    propertyAccess, typeof(object));

    // Lambda expression
    Expression<Func<object, object>> lambda =
    Expression.Lambda<Func<object, object>>(
    castPropertyValue, instance);
    this.m_getter = lambda.Compile();

    ParameterExpression paramEntityObj = Expression.Parameter(type, "t");
    ParameterExpression paramProVal = Expression.Parameter(typeof(object), "propertyVal");
    UnaryExpression paramProVal2 = Expression.Convert(paramProVal, typeof(object));
    MemberExpression me = Expression.Property(paramEntityObj, "Value");

    MethodCallExpression body = Expression.Call(paramEntityObj, type.GetMethod("set_" + propertyInfo.Name), paramProVal2);
    Expression<Action<Temp, object>> setPropertyExpression = Expression.Lambda<Action<Temp, object>>(body, paramEntityObj, paramProVal);

    Action<Temp, object> setPropertyAction = setPropertyExpression.Compile();

    this.m_setter = setPropertyExpression.Compile();

    }

    public object GetValue(object o)
    {
    return this.m_getter(o);
    }

    public void SetValue(object o)
    {
    this.m_setter(entity,o);
    }
    }

    调用
    DynamicPropertyAccessor property = new DynamicPropertyAccessor(t, "Value");
    property.SetValue("sddd");
    Console.WriteLine(t.Value.ToString());

  45. davin
    *.*.*.*
    链接

    davin 2009-01-09 00:27:00

    又见赵老师佳作了!看来读1,2遍是不能完全明白的,呵呵.在大约2个小时之前看了一篇老外Terry Aney写的 LINQ to SQLBatch Updates and Deletes 的文章,细看下去才知道terry 写的这篇文章(做了补充和改进)最初源自你的英文blog(很久没更新了哈).不由得激动了一下,可是第一次(可能我的阅读量太少)看到老外们从我们的blog上获取资源了.愿老赵再接再厉,我希望能能看到更多类似于 In Jeffrey's article ...。

  46. davin
    *.*.*.*
    链接

    davin 2009-01-09 00:45:00

    临睡前想到一个问题,如你文中所指"可以获取对象生层次的属性<%# Eval("Content.Length") %>"这个属性包括也包括entity.refEntity.property(对象的关联对象的属性),当然这里只考虑实体对象的1:1或n:1的关系而?如果包括,那我该如何入手,望指点一二!

  47. 怪怪
    *.*.*.*
    链接

    怪怪 2009-01-09 02:00:00

    @Jeffrey Zhao
    呃,你是指你文章中的吗? 那我指的不是这种,而是“把泛型当作类型字典用”的方法,不过后面这种方法就要求调用时必须明确指明类型了。这也是脑袋好几年前泛型刚出没多久时候弄的了,也不太新鲜了。

    关于性能的话题,大多数时候性能的问题和任何其它问题一样,都是因为代码对事物的描述有偏差,所以才产生,哪怕是细枝末节的。只是不严重的时候我们就不去管它了。

    包括这个Eval和其它一些各种各样的损失(不仅仅是性能上的),实质上是因为ASP.NET中的一些模型离真正的贴切描述相差一步,其实现又离设计者的构思相差一步,才造成的。

    不煞风景了,总而言之,你这个实现确实要比玩IL舒服也安全,顶你一下呵呵。

  48. 老赵
    admin
    链接

    老赵 2009-01-09 02:12:00

    @davin
    没有听懂你的问题,再说一下?

  49. 老赵
    admin
    链接

    老赵 2009-01-09 02:13:00

    @怪怪
    哎,我还是没有跟上你的高度,呵呵……

  50. oec2003
    *.*.*.*
    链接

    oec2003 2009-01-09 08:34:00

    马上上班了 ,回家再看

  51. 啥事[未注册用户]
    *.*.*.*
    链接

    啥事[未注册用户] 2009-01-09 09:03:00

    老赵好像又胖了

  52. 菌哥
    *.*.*.*
    链接

    菌哥 2009-01-09 09:05:00

    先支持一下,再来慢慢品尝佳作!

  53. 老赵
    admin
    链接

    老赵 2009-01-09 09:06:00

    --引用--------------------------------------------------
    啥事: 老赵好像又胖了
    --------------------------------------------------------
    搞笑了……

  54. BZZ
    *.*.*.*
    链接

    BZZ 2009-01-09 09:08:00

    老赵有点像SKY

  55. 不要怪我太坦白[未注册用户]
    *.*.*.*
    链接

    不要怪我太坦白[未注册用户] 2009-01-09 09:14:00

    老赵,这篇文章你是昨天写的,
    今天又修改了一下,难道就是为了上“今日头条”?

  56. 自强不息
    *.*.*.*
    链接

    自强不息 2009-01-09 09:14:00

    不用Eval,还有别的方法绑定吗?还请各位明示

  57. 老赵
    admin
    链接

    老赵 2009-01-09 09:18:00

    --引用--------------------------------------------------
    不要怪我太坦白: 老赵,这篇文章你是昨天写的,
    今天又修改了一下,难道就是为了上“今日头条”?
    --------------------------------------------------------
    没错,我更新了,不顶一下就很少有人会看得到。

  58. gguowang
    *.*.*.*
    链接

    gguowang 2009-01-09 09:30:00

    没有做Web程序,来凑个热闹,感受一下强人的思想 受益了 谢谢 !

  59. xjb
    *.*.*.*
    链接

    xjb 2009-01-09 09:40:00

    老赵写的总给人意外的收获,思考的非常深呀

  60. IsSuchCloud[未注册用户]
    *.*.*.*
    链接

    IsSuchCloud[未注册用户] 2009-01-09 09:43:00

    还是老赵的方法简便啊

  61. 老赵
    admin
    链接

    老赵 2009-01-09 09:51:00

    --引用--------------------------------------------------
    gguowang: 没有做Web程序,来凑个热闹,感受一下强人的思想 受益了 谢谢 !
    --------------------------------------------------------
    这东西其实和Web无关的。事实上以前的反射调用方式总归可以通过类似这样的做法来实现来提高性能。

  62. 江大鱼
    *.*.*.*
    链接

    江大鱼 2009-01-09 09:59:00

    <%# FastEval("Content") %>
    这个怎么实现?

  63. airwolf2026
    *.*.*.*
    链接

    airwolf2026 2009-01-09 10:00:00

    那这个怎么说,linq to sql 也可以(或者就是用)这个Emit方式来?生成最终的sql?
    学了半年的asp.net 现在总算看懂直接Eval为啥会性能差些啦哈.曾经看'阿不'那个看傻了...

    对啦,请教个问题,目前俺组织打算让俺去做wince开发...(可能主要是c/c++开发),俺现在又觉得c#很好,特别现在的新特性,可以少编码至少可以偷懒,学校的时候主要学c++,知道很多东西都很麻烦.不知道该如何决定...

  64. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-01-09 10:04:00

    --引用--------------------------------------------------
    Jeffrey Zhao: --引用--------------------------------------------------
    朝晖的.net: 这篇挺不错的,受益匪浅。
    看着这个文章感觉偶要学习的东西还有好多啊。
    感觉老赵进入2009后迅速活跃起来了。
    --------------------------------------------------------
    老赵离江郎才尽永远只有3篇文章。
    --------------------------------------------------------
    老赵你还真实在 不可以把普遍现状说给人听啊


    这叫知无不言言无不尽 你不会说得好听点

  65. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-01-09 10:08:00

    另外 这么好的方式 感觉这迟早会被封装好内置
    希望老赵能把这个贡献到framework 社区 变成下一代framework的标准eval
    我们就免得理解那么多

  66. 太菜匿了[未注册用户]
    *.*.*.*
    链接

    太菜匿了[未注册用户] 2009-01-09 10:12:00

    不好意思,我有一个疑问..
    from c in comments
    from u in users
    where c.UserID == u.UserID
    order by c.CreateTime
    select new
    {
    Title = c.Title,
    Content = c.Content,
    NickName = u.NickName
    };
    这些为什么不让数据库去做呢?

  67. 文明的天空
    *.*.*.*
    链接

    文明的天空 2009-01-09 10:17:00

    @太菜匿了 可能赵哥只是想教我们一招,这里没有什么意义!

  68. 朝晖的.net
    *.*.*.*
    链接

    朝晖的.net 2009-01-09 10:19:00

    @太菜匿了

    简单点说因为orm的关系,采用oop的设计方法数据库里有张comments和users表,像这种结果
    {
    Title = c.Title,
    Content = c.Content,
    NickName = u.NickName
    };你用数据库做就得做设图,还得mapping一个不干净的对象出来接收结果。

  69. waterhua[未注册用户]
    *.*.*.*
    链接

    waterhua[未注册用户] 2009-01-09 10:25:00

    很多3.5的都没用到,因为目前大多数空间也只是到.NET2.0,哎

  70. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-01-09 10:30:00

    @waterhua
    空间的省下来也是省给别人 不如全占了
    灭哈哈哈

  71. Caspar Jiong
    *.*.*.*
    链接

    Caspar Jiong 2009-01-09 10:42:00

    这么好的文章,怎能不顶,研究研究

  72. 老赵
    admin
    链接

    老赵 2009-01-09 11:23:00

    --引用--------------------------------------------------
    江大鱼: <# FastEval("Content") %>
    这个怎么实现?
    --------------------------------------------------------
    没有看文章?

  73. 老赵
    admin
    链接

    老赵 2009-01-09 11:24:00

    --引用--------------------------------------------------
    airwolf2026: 那这个怎么说,linq to sql 也可以(或者就是用)这个Emit方式来?生成最终的sql?
    学了半年的asp.net 现在总算看懂直接Eval为啥会性能差些啦哈.曾经看'阿不'那个看傻了...

    对啦,请教个问题,目前俺组织打算让俺去做wince开发...(可能主要是c/c++开发),俺现在又觉得c#很好,特别现在的新特性,可以少编码至少可以偷懒,学校的时候主要学c++,知道很多东西都很麻烦.不知道该如何决定...
    --------------------------------------------------------
    linq to sql当然不是用Emit来做的。
    我也不知道该怎么决定……

  74. 老赵
    admin
    链接

    老赵 2009-01-09 11:26:00

    --引用--------------------------------------------------
    韦恩卑鄙: 另外 这么好的方式 感觉这迟早会被封装好内置
    希望老赵能把这个贡献到framework 社区 变成下一代framework的标准eval
    我们就免得理解那么多
    --------------------------------------------------------
    其实这些做法可以用在各种成员中,理论上可以替代大部分的反射调用,的确可以总结一下

  75. 老赵
    admin
    链接

    老赵 2009-01-09 11:26:00

    --引用--------------------------------------------------
    韦恩卑鄙:
    老赵你还真实在 不可以把普遍现状说给人听啊

    这叫知无不言言无不尽 你不会说得好听点
    --------------------------------------------------------
    不不,是我自己比较笨而已……

  76. 老赵
    admin
    链接

    老赵 2009-01-09 11:27:00

    --引用--------------------------------------------------
    太菜匿了: 不好意思,我有一个疑问..
    from c in comments
    from u in users
    where c.UserID == u.UserID
    order by c.CreateTime
    select new
    {
    Title = c.Title,
    Content = c.Content,
    NickName = u.NickName
    };
    这些为什么不让数据库去做呢?
    --------------------------------------------------------
    这是客户端结合多个数据集供显示,和数据库有什么关系。

  77. 古巴[未注册用户]
    *.*.*.*
    链接

    古巴[未注册用户] 2009-01-09 11:51:00

    一些细节还没完全理解,不过先问个问题,既然set是通过DynamicExecutor调用的GetSetMethod,那get为什么不类似的调用GetGetMethod呢?

  78. 老赵
    admin
    链接

    老赵 2009-01-09 11:54:00

    --引用--------------------------------------------------
    古巴: 一些细节还没完全理解,不过先问个问题,既然set是通过DynamicExecutor调用的GetSetMethod,那get为什么不类似的调用GetGetMethod呢?
    --------------------------------------------------------
    没错,也可以使用GetGetMethod,但是尝试之后会发现性能比直接访问属性略低50%左右。

  79. hahaer[未注册用户]
    *.*.*.*
    链接

    hahaer[未注册用户] 2009-01-09 11:57:00

    用Eval优雅吗?个人看起来乱糟糟的。

  80. 老赵
    admin
    链接

    老赵 2009-01-09 12:01:00

    @hahaer
    怎么说?

  81. 未上线的蒙蒙[未注册用户]
    *.*.*.*
    链接

    未上线的蒙蒙[未注册用户] 2009-01-09 12:43:00

    @Jeffrey Zhao
    老赵你明天到长宁路聚合吗?

  82. 老赵
    admin
    链接

    老赵 2009-01-09 12:46:00

    --引用--------------------------------------------------
    未上线的蒙蒙: @Jeffrey Zhao
    老赵你明天到长宁路聚合吗?
    --------------------------------------------------------
    晚上有事,下午就用来学习了,呵呵

  83. viwer[未注册用户]
    *.*.*.*
    链接

    viwer[未注册用户] 2009-01-09 13:18:00

    强人啊,用了这么几年都从没想过这个问题,PFPF!

  84. 小鬼00[未注册用户]
    *.*.*.*
    链接

    小鬼00[未注册用户] 2009-01-09 14:02:00

    好久没用控件了.

    反射确实是个好东西,结合具体的应用,使用不同的优化方法,反射的性能并不会成为应用上的瓶颈的.

  85. 天生俪姿
    *.*.*.*
    链接

    天生俪姿 2009-01-09 22:57:00

    dynamicpropertyaccessor-and-fasteval.html
    我想问一下 这个页面的链接地址是怎么生成出来的?
    英文的名称是你自己指定的吗?在哪里指定的。谢谢老赵。一个很不爽的问题。嘿嘿。

  86. overred
    *.*.*.*
    链接

    overred 2009-01-09 23:21:00

    顶一下。。可惜不搞web。。。
    Happy Coding阿

  87. 老赵
    admin
    链接

    老赵 2009-01-09 23:21:00

    @天生俪姿
    每篇文章都可以设啊

  88. 老赵
    admin
    链接

    老赵 2009-01-09 23:23:00

    @overred
    和Web没有必然联系

  89. win[未注册用户]
    *.*.*.*
    链接

    win[未注册用户] 2009-01-10 00:57:00

    好文章。。。

    顶一下。。。

  90. 装配脑袋
    *.*.*.*
    链接

    装配脑袋 2009-01-12 08:29:00

    还是编写Client程序好啊,我现在就毫无顾忌地使用反射。。。

  91. 老赵
    admin
    链接

    老赵 2009-01-12 09:13:00

    --引用--------------------------------------------------
    装配脑袋: 还是编写Client程序好啊,我现在就毫无顾忌地使用反射。。。
    --------------------------------------------------------
    其实也不会影响WebApp多少的——一回事。

  92. tensun
    *.*.*.*
    链接

    tensun 2009-01-12 15:58:00

    又学习了,
    我的第一个watch 居然是: 00:00:07.9052236
    看来楼主机器配置很好。。。

  93. tensun
    *.*.*.*
    链接

    tensun 2009-01-12 17:05:00

    不过本人对于Expression 不是很了解,
    对于DynamicPropertyAccessor类第二个构造函数里面的一系列 Expression
    实在是看得有点晕。。。

  94. JimLiu
    *.*.*.*
    链接

    JimLiu 2009-01-22 10:41:00

    支持老赵一下
    我觉得做技术的就是要保持清醒,“性能”和“性能瓶颈”本来就是两个概念,不应该人云亦云

  95. 老赵
    admin
    链接

    老赵 2009-01-22 10:54:00

    @JimLiu
    嗯,是。

  96. 魔方网[未注册用户]
    *.*.*.*
    链接

    魔方网[未注册用户] 2009-03-02 13:46:00

    确实是一片好文章,不得不顶!
    http://www.mofun.cc

  97. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-03-11 00:48:00

    扩展方法不能做到:

    <%# FastEval( xxx ) %>

    吧。

    只能做到:

    <%# this.FastEval( xxx ) %>


    扩展方法毕竟不是自己的方法,是不能省略this的。

  98. 老赵
    admin
    链接

    老赵 2009-03-11 00:50:00

    @Ivony...
    没错,如果很在意这点的话,可以把这些辅助方法定义到Page基类中。

  99. 菌哥
    *.*.*.*
    链接

    菌哥 2009-04-01 20:51:00

    100楼,我支持老赵,有志不在年高,真的,我挺佩服老赵的(其实是小赵)

  100. 老赵
    admin
    链接

    老赵 2009-04-01 23:02:00

    @菌哥
    多谢支持……

  101. Sail
    *.*.*.*
    链接

    Sail 2009-04-03 23:44:00

    老赵 你的字 能不能搞小点,拖来拖去 看着累

  102. 文明的天空
    *.*.*.*
    链接

    文明的天空 2009-04-06 09:46:00

    谢谢赵哥!!

  103. YJJ
    *.*.*.*
    链接

    YJJ 2009-09-27 10:47:00

    看到一半,发现老赵太风趣了
    哈哈
    先回复下再接着看.........

  104. 未登录....[未注册用户]
    *.*.*.*
    链接

    未登录....[未注册用户] 2009-10-17 12:34:00

    赵老师为什么我通过调用TestDynamic方法比反射花的时间要多的多?您帮我看一下是哪里出了问题...
    protected void Page_Load(object sender, EventArgs e)
    {
    UserInfo userInfo = new UserInfo { UserName = "aaa" };

    PropertyInfo pi = userInfo.GetType().GetProperty("UserName");
    Stopwatch s = new Stopwatch();
    s.Start();
    for (int i = 0; i < 10000; i++)
    {
    var value = pi.GetValue(userInfo, null);
    }
    s.Stop();
    Response.Write(s.Elapsed);
    Stopwatch s1 = new Stopwatch();
    s1.Start();
    for (int i = 0; i < 10000; i++)
    {
    var value = TestDynamic(pi, userInfo);
    }
    s1.Stop();
    Response.Write("<br/>" + s1.Elapsed);
    }
    object TestDynamic(PropertyInfo property, object obj)
    {
    ParameterExpression o = Expression.Parameter(typeof(object), "instance");
    Expression<Func<object, object>> func = Expression.Lambda<Func<object, object>>(
    Expression.Convert(
    Expression.Property(
    Expression.Convert(o, property.ReflectedType), property),
    typeof(object)),o);
    return func.Compile()(obj);
    }

  105. 未登录.....[未注册用户]
    *.*.*.*
    链接

    未登录.....[未注册用户] 2009-10-17 17:17:00

    赵老师,帮我看一下.....谢谢了

  106. 老赵
    admin
    链接

    老赵 2009-10-17 17:37:00

    @ 未登录.....
    Compile是最花时间的,正确的做法是Compile一次然后多次调用。
    // 下次发代码,用博客园的代码插入功能吧。

  107. 未登录.....[未注册用户]
    *.*.*.*
    链接

    未登录.....[未注册用户] 2009-10-17 18:14:00

    @Jeffrey Zhao
    太感谢了...就这一句话就行了。。。虽然以前就知道compile最花时间...今天就没想到...

  108. Everlonely
    *.*.*.*
    链接

    Everlonely 2010-01-11 15:47:00

    这个好像不能用于匿名类型,会爆error的

  109. Everlonely
    *.*.*.*
    链接

    Everlonely 2010-01-11 15:52:00

    不好意思,我自己弄错了。测试过了,匿名类型也是OK的。。。

  110. NanaLich
    124.114.154.*
    链接

    NanaLich 2010-04-06 12:35:03

    我可以在分享给别人的lib里面用老赵的这些辅助方法吗?如果可以的话,我需要怎么样说明呢?

  111. 老赵
    admin
    链接

    老赵 2010-04-06 13:40:20

    @NanaLich: 我可以在分享给别人的lib里面用老赵的这些辅助方法吗?如果可以的话,我需要怎么样说明呢?

    当然可以,说明的话其实不强求,如果可以的话,放一个URL就OK了。

  112. 老菜
    123.133.161.*
    链接

    老菜 2010-05-14 23:51:20

    先记号再看。

    这个博客是否有这样的功能:查找我所有回复,进而找到我所有回复过的文章?

  113. 看看
    222.92.42.*
    链接

    看看 2010-05-17 13:32:28

    今天通天老赵头条才看到啊。。不过后面那个SetValue时这样不可以吗?

    ParameterExpression value = Expression.Parameter(typeof(object), "Value");
    Expression convertVale = Expression.Convert(value, property.Type);
    BinaryExpression equal = Expression.Equal(property, convertVale);
    
  114. 老赵
    admin
    链接

    老赵 2010-05-17 13:38:54

    @看看

    我觉得这个再明显不过了,自己尝试一下吧。

  115. 看看
    222.92.42.*
    链接

    看看 2010-05-17 13:49:49

    回的真快啊,刚想明白。那个是个属性,不是值。。。。

  116. 老赵
    admin
    链接

    老赵 2010-05-17 17:33:10

    @看看

    真不是这个问题。

  117. 看看
    222.92.42.*
    链接

    看看 2010-05-18 08:46:06

    多谢老赵。自己不太认真,乱猜原因。晕,不过没想到Expression.Equal相当于==,不过我还有个疑问,Expression里面没有赋值运算的吗?

  118. 老赵
    admin
    链接

    老赵 2010-05-18 10:46:31

    @看看

    严格说来赋值是Statement不是Expression。

  119. 链接

    tsorgy 2010-08-12 11:57:37

    在老赵的上一篇《方法的直接调用,反射调用与……Lambda表达式调用》中我提出了在实际环境中大量构造Expression的耗时问题,看了这一篇文章豁然开朗啊,缓存解决。

    的确,我还是缺少项目经验啊,老赵的文章让我获益匪浅。

    使用缓存技术以后,两者在绝对使用时间上已经看不出差别(反射三个object,每个object有不同的几个属性,ms为单位),但在CPU周期数上从100W、40W、30W次下降到了20W、7W、6W次。。有了显著的提高。特别是检索大量数据时我相信差距会相当明显。。

  120. bugsharp
    116.228.220.*
    链接

    bugsharp 2010-09-09 15:49:21

    如果Temp里面想给多个属性赋值 ?如何做到!!不好意思刚接触新手

    class Temp
    {
        public int Value { get; set; }
        public string Name {get; set }
    }
    

    要这样吗?

    DynamicPropertyAccessor property = new DynamicPropertyAccessor(t.GetType(), "Name");
    
  121. bugsharp
    116.228.220.*
    链接

    bugsharp 2010-09-09 18:02:11

    还有一点:

    for (var i = 0; i < 1000000; i++)
    {
        var value = propertyInfo.GetValue(ll[0], null);
    }
    

    这样循环取出来的数据都一样,我不明白这有什么意义;而真正的我想的用法是:

    List<Temp> ll = new List<Temp>();
    for (int i = 0; i < 10000000; i++)
    {
        Temp tt = new Temp();
        tt.Name = i++;
        ll.Add(tt);
    }
    
    DynamicPropertyAccessor property = c.GetAccessor(ll[0].GetType(), "Name");
    foreach (Temp td in ll)
    {
        DynamicPropertyAccessor propertyValue = c.GetAccessor(td.GetType(), "Value");
        //拿出不同的值;但这样感觉和反射的效率又差不多!!
        object values = property.GetValue(td);
    }
    

    请明示!!!!!!!!

  122. bugsharp
    116.228.220.*
    链接

    bugsharp 2010-09-09 18:12:16

    不好意思用for 代替foreach就可以了

  123. 老赵
    admin
    链接

    老赵 2010-09-10 00:27:50

    @bugsharp

    你没看明白这个DynamicPropertyAccessor是怎么用的,自然效率上不去了。

    还有,我那么好的评论实时预览机制放在这里,你为什么还能发格式这么乱七八糟的评论上去。我很难想像如果是认真写程序的人,就能这么无所谓代码样式。

  124. bugsharp
    116.228.220.*
    链接

    bugsharp 2010-09-10 10:03:52

    评论实时预览机制我要敲两次回车,才能换行的!(在Chrome下面;)当时不注意下面的预览机制!!

  125. bugsharp
    116.228.220.*
    链接

    bugsharp 2010-09-10 11:08:38

    真心地谢谢您的好文章,让我学会了如何构建表达式;

    一直关注您。。。

  126. 老赵
    admin
    链接

    老赵 2010-09-10 11:24:04

    @bugsharp

    认真点吧,预览结果看出来乱七八糟的,就看看帮助……

  127. gsralex
    115.58.236.*
    链接

    gsralex 2012-01-24 08:51:10

    在我这里测试,PropertyInfo.GetValue(obj,obj[] index);

    要比用表达式树 Expression.Property快上不少,测试数据 1-10000,趋势一致

  128. 老赵
    admin
    链接

    老赵 2012-01-25 14:58:50

    @gsralex

    肯定是测试方法错了,公布下代码吧。

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我