开发者

Is there a fast version of DataBinder.Eval for C#?

I'm looking to see if a fast version of ASP.NET's System.Web.UI.DataBinder.Eval() exists? Ideally so开发者_StackOverflow社区mething that compiles to a Func that I can cache and call later, like:

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

Does anyone know if such a beast exists?

P.S. I'm not using ASP.NET and would like it to work in normal C#


The more I look at it, the more I want to say:

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

if you need it based on a string, the Expression API is pretty fair there.

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; }
}


Here's something that should get you started:

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;
    }
}


I'm a little late to the game, but this was my solution.

I added this private method to a string Extension class called FormatWith Removing the DataBinder reference in favor for this method.

#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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜