c# - 将 Lambda 表达式树转换预编译为常量?

标签 c# .net linq

采用表达式树并将其转换为某种其他形式,例如字符串表示(例如 this questionthis question ,我怀疑 Linq2Sql 会做类似的事情)是相当常见的。

在很多情况下,甚至可能是大多数情况下,表达式树转换总是相同的,即如果我有一个函数

public string GenerateSomeSql(Expression<Func<TResult, TProperty>> expression)

然后任何具有相同参数的调用将始终返回相同的结果,例如:

GenerateSomeSql(x => x.Age)  //suppose this will always return "select Age from Person"
GenerateSomeSql(x => x.Ssn)  //suppose this will always return "select Ssn from Person"

因此,从本质上讲,带有特定参数的函数调用实际上只是一个常量,只是在运行时不断地重新计算它会浪费时间。

为了论证,假设转换足够复杂以导致明显的性能下降,是否有任何方法可以将函数调用预编译为实际常量?

编辑 似乎没有办法在 C# 本身内完全做到这一点。您可能在 c# 中得到的最接近的答案是公认的答案(尽管您当然希望确保缓存本身不比重新生成慢)。要实际转换为真正的常量,我怀疑通过一些工作,您可以使用类似 mono-cecil 的东西在编译后修改字节码。

最佳答案

优秀LINQ IQueryable Toolkit project 有一个查询缓存,它的功能与您所描述的类似。它包含一个 ExpressionComparer 类,该类遍历两个表达式的层次结构并确定它们是否相等。此技术还用于收集对公共(public)属性的引用以进行参数化和删除冗余连接。

您需要做的就是想出一个表达式哈希策略,这样您就可以将处理过的表达式的结果存储在字典中,以备将来重用。

你的方法看起来像这样:

private readonly IDictionary<Expression, string> _cache
    = new Dictionary<Expression, string>(new ExpressionEqualityComparer());

public string GenerateSomeSql(Expression<Func<TResult, TProperty>> expression)
{
    string sql;
    if (!_cache.TryGetValue(expression, out sql))
    {
        //process expression
        _cache.Add(expression, sql);
    }
    return sql;
}

class ExpressionEqualityComparer : IEqualityComparer<Expression>
{
    public bool Equals(Expression x, Expression y)
    {
        return ExpressionComparer.AreEqual(x, y);
    }

    public int GetHashCode(Expression obj)
    {
        return ExpressionHasher.GetHash(obj);
    }
}

关于c# - 将 Lambda 表达式树转换预编译为常量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3058181/

相关文章:

c# - csproj:如何获取所有资源?

c# - 发布期间出错无法删除目录 "bin\Debug\app.publish\"

c# - 我怎样才能在 linq asp.net mvc 5 中拥有动态的 where 条件?

c# - Linq To SQL - 具有和分组依据

c# - 使用正则表达式查找并替换特定数字

c# - 如何使用必需的非空列设置 filehelpers

.net - 使用 List.collect f#

c# - 由于内部错误,服务器无法处理请求

asp.net-mvc - 操作可能会破坏运行时的稳定性 : LinqToSQL

c# - 如何在 C# 中将 Int/Decimal 转换为 float?