所以,如果我理解正確的話,你想創建一個使用你的傳遞函數的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函數內使用的本地範圍變量會自動捕獲並保持可用狀態。
現在當然你也可以創建它作爲一個表達式來存儲編譯的函數,但是我認爲這樣做更具可讀性和可維護性。
我不明白。爲什麼不能簡單地在表達式樹中調用'formattingExpression.Compile()'? – svick