2011-04-13 27 views
3

我在看ASP.NET的System.Web.UI.DataBinder.Eval()的快速版本是否存在? 理想的东西,编译成,我可以缓存,然后再调用,就像一个FUNC:C#有DataBinder.Eval的快速​​版本吗?

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

有谁知道,如果这样一个东西存在?

P.S.我不使用ASP.NET和希望它在普通的C#工作

+2

您目前遇到了一些性能问题,由于经典'Eval'方法?如果是的话,你能否解释一下你的情况,展示你正在使用的代码,评论你在执行负载测试时得到的结果,从而得出这个结论?如果不是,你为什么需要这个? – 2011-04-13 22:11:23

+0

因为我真的关心性能,不想在编译的模板中包含低效的执行路径。 – mythz 2011-04-13 22:13:46

+0

@mythz,'Eval'并不低效。许多繁忙的交通网站正在使用它。 – 2011-04-13 22:14:21

回答

6

越我看它,我就越想说:

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

嗨马克,不幸的是,字符串只在运行时才知道。 – mythz 2011-04-14 10:27:23

+0

@mythz - 请参阅更新 – 2011-04-14 10:30:46

+0

@mythz - note我收紧了一些代码以处理一些边缘情况 – 2011-04-14 10:34:29

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