So, if I understand you correctly, you want to create a lambda (expression) which uses your passed function and does some additional work around it. So you essentially just want to use this function inside of an expression.
At this point, allow me to suggest that you don’t even use expressions. You could just create a function that takes a Func<DateTime, string> parameter and uses that to process something. But in case you really need the expression for something, I’ll just try to explain how to build one.
For this example, I’ll be creating this function:
string MonthAndDayToString (int month, int day)
{
return "'" + formattingFunction(new DateTime(2013, month, day)) + "'"
}
As you can see, I’m going to create a Func<int, int, string> which then creates the DateTime object and passes it to the function and then further changes the result.
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!'
After looking at Alex’ answer, it seems that I misunderstood your question and tried to solve the reverse of what you are doing. But it’s not all too different to change it to what you are actually trying to do:
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)));
But I’d still argue that a normal function that takes a Func<DateTime, string> and a DateTime parameter would be a lot easier to maintain. So unless you really need the expressions, avoid them.
Why I still don’t think you really need expressions for this. Consider this example:
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'
}
As you can see, I’m only constructing the formatting logic function once, lazily when it’s not yet set. That’s when the reflection runs to get some values you are using somewhere in the function. As the function is created as a lambda function, the variables we use from the local scope within the lambda function are automatically captured and kept available.
Now of course you could also create this as an expression instead and store the compiled function, but I’d argue that doing it like this is a lot more readable and maintainable.
formattingExpression.Compile()inside the expression tree?