【问题标题】:Is there a fast version of DataBinder.Eval for C#?是否有适用于 C# 的快速版本的 DataBinder.Eval?
【发布时间】:2011-04-13 22:06:23
【问题描述】:

我正在寻找 ASP.NET 的 System.Web.UI.DataBinder.Eval() 的快速版本是否存在? 理想情况下,可以编译为 Func 的东西,我可以缓存并稍后调用,例如:

Func<object,string> expr = CompileDataBinder(typeof(Model), "model.PocoProperty.Name");
string propertyName = expr(model);

有人知道这样的野兽是否存在吗?

附:我没有使用 ASP.NET,希望它在普通 C# 中工作

【问题讨论】:

  • 您目前是否因为经典的Eval 方法而遇到一些性能问题?如果是,你能解释你的场景,展示你正在使用的代码,评论你在执行负载测试时获得的结果,从而得出这个结论吗?如果不是,你为什么需要这个?
  • 因为我实际上关心性能,并且不想在我编译的模板中包含低效的执行路径。
  • @mythz, Eval 不是低效的。许多流量大的网站都在使用它。
  • 我可以不用效率比等效的强类型转换 + 属性访问慢 300 倍。
  • @Darin 您的第一条评论令人沮丧地表现出我在处理 .NET 文化时每天面临的典型惯性。作为许多 NoSQL 论坛的成员,我可以说这不会发生在我必须证明我为什么要维护高性能系统的任何其他平台上。我很惊讶 172k 你是一个长期的 SO 用户,却没有意识到让 SO 使用起来如此愉快的主要原因之一(goo.gl/G85ehgoo.gl/fm9Zl)。我已经尝试阐明为什么它如此重要 github.com/mythz/ScalingDotNET 但却被置若罔闻,你的支持是典型而悲伤的。

标签: c# compilation eval expression


【解决方案1】:

越看越想说:

Func<Model,string> expr = model => model.PocoProperty.Name;

如果您需要它基于字符串,Expression API 在那里相当公平。

class Program
{
    static void Main(string[] args)
    {
        Func<object, string> expr = CompileDataBinder(typeof(Model), "PocoProperty.Name");

        var model = new Model { PocoProperty = new ModelPoco { Name = "Foo" } };

        string propertyName = expr(model);
    }
    static Func<object, string> CompileDataBinder(Type type, string expr)
    {
        var param = Expression.Parameter(typeof(object));
        Expression body = Expression.Convert(param, type);
        var members = expr.Split('.');
        for (int i = 0; i < members.Length;i++ )
        {
            body = Expression.PropertyOrField(body, members[i]);
        }
        var method = typeof(Convert).GetMethod("ToString", BindingFlags.Static | BindingFlags.Public,
            null, new Type[] { body.Type }, null);
        if (method == null)
        {
            method = typeof(Convert).GetMethod("ToString", BindingFlags.Static | BindingFlags.Public,
                null, new Type[] { typeof(object)}, null);
            body = Expression.Call(method, Expression.Convert(body, typeof(object)));
        }
        else
        {
            body = Expression.Call(method, body);
        }

        return Expression.Lambda<Func<object, string>>(body, param).Compile();
    }
}

class Model
{
    public ModelPoco PocoProperty { get; set; }
}
class ModelPoco
{
    public string Name { get; set; }
}

【讨论】:

  • 嗨,Marc,不幸的是,该字符串仅在运行时才知道。
  • @mythz - 注意我稍微收紧了代码以处理一些边缘情况
【解决方案2】:

以下内容应该可以帮助您入门:

using System;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;


class Person
{
    public int Id { get; set; }
    public FullName FullName { get; set; }
}

class FullName
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}


class Program
{
    static void Main(string[] args)
    {
        Person model = new Person
        {
            Id = 123,
            FullName = new FullName
            {
                FirstName = "Duncan",
                LastName = "Smart",
            }
        };

        var nameBinder = CompileDataBinder<Person, string>("model.FullName.FirstName");
        string fname = nameBinder(model);
        Debug.Assert(fname == "Duncan");

        // Note how here we pretend we don't know TProp type
        var idBinder = CompileDataBinder<Person, object>("model.Id");
        object id = idBinder(model);
        Debug.Assert(id.Equals(123));
    }

    static Func<TModel, TProp> CompileDataBinder<TModel, TProp>(string expression)
    {
        var propNames = expression.Split('.');

        var model = Expression.Parameter(typeof(TModel), "model");

        Expression body = model;
        foreach (string propName in propNames.Skip(1))
            body = Expression.Property(body, propName);
        //Debug.WriteLine(prop);

        if (body.Type != typeof(TProp))
            body = Expression.Convert(body, typeof(TProp));

        Func<TModel, TProp> func = Expression.Lambda<Func<TModel, TProp>>(body, model).Compile();
        //TODO: cache funcs
        return func;
    }
}

【讨论】:

    【解决方案3】:

    我玩游戏有点晚了,但这是我的解决方案。

    我将此私有方法添加到名为 FormatWith 的字符串扩展类中,删除 DataBinder 引用以支持此方法。

    #nullable enable
            private static object? Eval(object source, string valueName)
            {
                MemberInfo[] miList = source.GetType().GetMember(valueName);
                foreach (var mi in miList)
                {
                    if (mi is PropertyInfo)
                    {
    
                        PropertyInfo? pi = mi as PropertyInfo;
                        if (pi != null && pi.CanRead)
                        {
                            return pi.GetValue(source);
                        }
                    }
                    else if (mi is FieldInfo)
                    {
                        FieldInfo? fi = mi as FieldInfo;
                        if (fi != null)
                        {
                            return fi.GetValue(source);
                        }
                    }
                }
                return null;
            }
    #nullable disable
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-10
      • 2017-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多