所以,如果我对您的理解正确,您想创建一个 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 函数内的本地范围内使用的变量会被自动捕获并保持可用。
当然,您也可以将其创建为表达式并存储编译后的函数,但我认为这样做更具可读性和可维护性。