gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 23:35:06 25 4
gpt4 key购买 nike

采用表达式树并将其转换为某种其他形式,例如字符串表示(例如 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com