假设我们有以下代码:
ExpressionHelper.GetRouteValuesFromExpression<AccountController>(ax => ax.MyAction("a", "b"));
(来自ASP.NET MVC Futures程序集)。方法相当快 - 它在150ms内执行10k次迭代。
现在,我们将代码更改为:
string a = "a";
string b = "b";
ExpressionHelper.GetRouteValuesFromExpression<AccountController>(ax => ax.MyAction(a, b));
此代码将在15 秒内执行10k次迭代
问题是以下代码:
Expression<Func<object>> lambdaExpression = Expression.Lambda<Func<object>>(Expression.Convert(arg, typeof (object)));
Func<object> func = lambdaExpression.Compile();
value = func()
有没有更好的方法从表达式获取值而不是每次编译表达式?这可以极大地影响ASP.NET MVC链接生成速度。
答案 0 :(得分:1)
为什么不在本地缓存表达式的值及其编译值?如果这是一个瓶颈?我想一个简单的词典可以解决这个问题:
Dictionary<Expression<Action<T>>, Action<T>> m_Cache =
new Dictionary<Expression<Action<T>>, Action<T>>();
public void GetRouteValuesFromExpression<T>(Expression<Action<T>> expr) {
Action<T> compiled = null;
if (!m_Cache.TryGetValue(expr, ref compiled)) {
compiled = expr.Compile();
m_Cached.Add(expr, compiled);
}
// execute …
}
答案 1 :(得分:0)
是否必须是Func<object>
?您可以手动制作“捕获” - 即具有声明&amp; b;有Func<Whatever, object>
,并将其编译为委托。然后你在运行时所做的就是:
Foo foo = new Foo {A = a, B = b};
return cachedFunc(foo);
我不太确定Convert(blah,typeof(object))正在做什么 - 你能澄清一下吗?我对表达方式有很多经验,但这似乎......不寻常......
答案 2 :(得分:0)
我已经摆弄了一下,想出了以下内容:
var body = (MethodCallExpression)expr.Body;
var arg1 = (MemberExpression)body.Arguments[0];
var contextType = arg1.Member.DeclaringType;
var field = contextType.GetField(arg1.Member.Name);
Console.WriteLine(field.GetValue(…));
假设expr
是您的Expression<Action<T>>
参数,这会为您提供反射字段,该字段作为您调用的第一个参数传递(在您的情况下为a
)。但是,我无法提取评估此字段所需的上下文(最后一行,标有“...”的位置)。我相信如果没有汇编表达式,就无法访问这个上下文。因此,你想要的是不可能的。
请证明我错了。 ; - )
(实际上,我不太确定,因为即使使用Reflector我也无法找到存储执行上下文的位置,所以我可能会忽略某些内容。)