gpt4 book ai didi

c# - 评估 Lambda 表达式作为表达式树的一部分

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

我正在尝试使用表达式树构建一个 lambda 表达式。这是我要创建的 lambda 表达式的格式:

Func<DateTime, string> requiredLambda = dt =>
{
var formattedDate = dt.ToShortDateString();

/**
* The logic is not important here - what is important is that I
* am using the result of the executed lambda expression.
* */
var builder = new StringBuilder();
builder.Append(formattedDate);
builder.Append(" Hello!");
return builder.ToString();
};

要注意的是,我并不是从头开始构建这棵树 - 格式化逻辑已经以 Expression<Func<DateTime, string>> 实例的形式交给我了- 说:

Expression<Func<DateTime, string>> formattingExpression = dt => dt.ToShortDateString();

我知道我可以调用表达式树的外部

formattingExpression.Compile()(new DateTime(2003, 2, 1)) 

评估表达式 - 但问题是我希望在表达式树评估和分配它 - 允许我对表达式树内的结果执行额外的逻辑。

到目前为止,我没有想出任何解决办法 - 几乎可以肯定是对表达式树工作原理的误解。非常感谢任何帮助!

最佳答案

因此,如果我理解正确的话,您想创建一个 lambda(表达式),它使用您传递的函数并围绕它做一些额外的工作。因此,您基本上只想在表达式内部使用此函数。

在这一点上,请允许我建议您甚至不要使用表达式。你可以只创建一个函数,它接受 Func<DateTime, string>参数并使用它来处理某些东西。但是,如果您真的需要某些东西的表达式,我会尝试解释如何构建一个。

对于这个例子,我将创建这个函数:

string MonthAndDayToString (int month, int day)
{
return "'" + formattingFunction(new DateTime(2013, month, day)) + "'"
}

如您所见,我将创建一个 Func<int, int, string>然后创建 DateTime对象并将其传递给函数,然后进一步更改结果。

Func<DateTime, string> formatting = dt => (...) // as above

// define parameters for the lambda expression
ParameterExpression monthParam = Expression.Parameter(typeof(int));
ParameterExpression dayParam = Expression.Parameter(typeof(int));

// look up DateTime constructor
ConstructorInfo ci = typeof(DateTime).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int) });

// look up string.Concat
MethodInfo concat = typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string), typeof(string) });

// inner call: formatting(new DateTime(2013, month, day))
var call = Expression.Call(formatting.Method, Expression.New(ci, Expression.Constant(2013), monthParam, dayParam));

// concat: "'" + call + "'"
var expr = Expression.Call(concat, Expression.Constant("'"), call, Expression.Constant("'"));

// create the final lambda: (int, int) => expr
var lambda = Expression.Lambda<Func<int, int, string>>(expr, new ParameterExpression[] { monthParam, dayParam });

// compile and execute
Func<int, int, string> func = lambda.Compile();
Console.WriteLine(func(2, 1)); // '01.02.2013 Hello!'
Console.WriteLine(func(11, 26)); // '26.11.2013 Hello!'

看了亚历克斯的回答后,我似乎误解了你的问题,并试图解决你所做的相反的事情。但是将其更改为您实际尝试做的事情并没有太大的不同:

Func<DateTime, string> formatting = dt => dt.ToShortDateString();

ParameterExpression param = Expression.Parameter(typeof(DateTime));
MethodInfo concat = typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string), typeof(string) });

var call = Expression.Call(formatting.Method, param);
var expr = Expression.Call(concat, Expression.Constant("'"), call, Expression.Constant(" Hello!'"));
var lambda = Expression.Lambda<Func<DateTime, string>>(expr, new ParameterExpression[] { param });

Func<DateTime, string> func = lambda.Compile();
Console.WriteLine(func(new DateTime(2013, 02, 01)));
Console.WriteLine(func(new DateTime(2013, 11, 26)));

但我仍然认为一个接受 Func<DateTime, string> 的普通函数和一个 DateTime参数将更容易维护。因此,除非您真的需要这些表达式,否则请避免使用它们。


为什么我仍然认为您真的不需要表达式。考虑这个例子:

private Func<DateTime, string> formatting = dt => dt.ToShortDateString();
private Func<DateTime, string> formattingLogic = null;

public Func<DateTime, string> FormattingLogic
{
get
{
if (formattingLogic == null)
{
// some results from reflection
string word = "Hello";
string quote = "'";

formattingLogic = dt =>
{
StringBuilder str = new StringBuilder(quote);
str.Append(formatting(dt));

if (!string.IsNullOrWhiteSpace(word))
str.Append(" ").Append(word);

str.Append(quote);
return str.ToString();
};
}

return formattingLogic;
}
}

void Main()
{
Console.WriteLine(FormattingLogic(new DateTime(2013, 02, 01))); // '01.02.2013 Hello'
Console.WriteLine(FormattingLogic(new DateTime(2013, 11, 26))); // '26.11.2013 Hello'
}

如您所见,我只构造了一次格式化逻辑函数,在尚未设置时懒惰地构造。那是反射运行以获取您在函数某处使用的某些值的时候。由于该函数是作为 lambda 函数创建的,因此我们在 lambda 函数内使用的局部范围内的变量会自动捕获并保持可用。

当然,现在您也可以将其创建为表达式并存储编译后的函数,但我认为这样做更具可读性和可维护性。

关于c# - 评估 Lambda 表达式作为表达式树的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20214965/

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