1

假设我们有以下代码:

ExpressionHelper.GetRouteValuesFromExpression<AccountController>(ax => ax.MyAction("a", "b"));

(来自 ASP.NET MVC 期货程序集)。方法相当快 - 它在 150 毫秒内执行 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 链接生成速度。

4

3 回答 3

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 …
}
于 2008-10-20T13:37:32.760 回答
0

它必须是一个Func<object>吗?您可能可以手动制作“捕获” - 即具有声明 a & b; 的类型。有Func<Whatever, object>, 并将其编译为委托。那么你在运行时所做的就是:

Foo foo = new Foo {A = a, B = b};
return cachedFunc(foo);

我不太确定 Convert(blah, typeof(object)) 正在做什么 - 你能澄清一下吗?我对表情有相当多的经验,但这似乎……不寻常……

于 2008-10-20T14:11:40.723 回答
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在您的情况下)。但是,我无法提取评估该字段所需的上下文(最后一行,位置标记为“...”)。我相信如果不编译表达式,就无法访​​问此上下文。结果,你想要的东西是不可能的。

证明我错了。;-)

(实际上,我不太确定,因为即使使用反射器我也无法找到执行上下文的存储位置,所以我可能会忽略一些东西。)

于 2008-10-20T14:38:18.753 回答