将lambda表达式转换为用于缓存的唯一键

Jam*_*uth 10 c# linq caching linq-expressions

我已经看过类似这个问题的其他问题,但我找不到任何可行的答案.

我一直在使用以下代码生成唯一键,用于将我的linq查询的结果存储到缓存中.

    string key = ((LambdaExpression)expression).Body.ToString();

    foreach (ParameterExpression param in expression.Parameters)
    {
        string name = param.Name;
        string typeName = param.Type.Name;

        key = key.Replace(name + ".", typeName + ".");
    }

    return key;
Run Code Online (Sandbox Code Playgroud)

它似乎适用于包含整数或布尔值的简单查询,但是当我的查询包含嵌套的常量表达式时,例如

// Get all the crops on a farm where the slug matches the given slug.
(x => x.Crops.Any(y => slug == y.Slug) && x.Deleted == false)
Run Code Online (Sandbox Code Playgroud)

返回的密钥是:

(True AndAlso(Farm.Crops.Any(y =>(value(OzFarmGuide.Controllers.FarmController + <> c__DisplayClassd).slug == y.Slug))AndAlso(Farm.Deleted == False)))

正如您所看到的,我传递的任何裁剪名称都会给出相同的关键结果.有没有办法可以提取给定参数的值,以便我可以区分我的查询?

还转换y为说出正确的类型名称会很好.....

svi*_*ick 5

正如Polity和Marc在他们的评论中所说,你需要的是LINQ表达式的部分评估者.您可以ExpressionVisitorMatt Warren的LINQ:构建IQueryable Provider - 第三部分中阅读如何使用它.由Pete Montgomery(链接到Polity)缓存LINQ查询结果的文章描述了关于这种缓存的一些更具体的细节,例如如何在查询中表示集合.

另外,我不确定我会这样依赖ToString().我认为它主要用于调试目的,并且可能在将来发生变化.另一种方法是创建自己的IEqualityComparer<Expression>,可以为任何表达式创建哈希代码,并可以比较两个表达式的相等性.我也可能会这样做ExpressionVisitor,但这样做会非常繁琐.