I have simple lambda as a string:
var str = "f => f.Substring(0, f.IndexOf(' '))";
which eventualy takes first word from the passed string.
What is the easiest way to compile/convert this peace of string into Func and make the following code to work.
Func<string, string> func = ...
var firstWord = func("Hello World");
Will Expression help me? Will appreciate working sample,
Thanks
Problem is that there is no strong typing support here, so you can't even utilize expression trees. However, DynamicLinq already does this, so you can easily get this working with a few modifications. Just create a few static methods of your own in the DynamicExpression class to add this functionality:
public static Expression<Func<T, S>> ParseLambda<T, S>(string expression)
{
string paramString = expression.Substring(0, expression.IndexOf("=>")).Trim();
string lambdaString = expression.Substring(expression.IndexOf("=>") + 2).Trim();
ParameterExpression param = Expression.Parameter(typeof(T), paramString);
return (Expression<Func<T,S>>)ParseLambda(new[] { param }, typeof(S), lambdaString, null);
}
public static LambdaExpression ParseLambda(string expression, Type returnType, params Type[] paramTypes)
{
string paramString = expression.Substring(0, expression.IndexOf("=>")).Trim("() ".ToCharArray());
string lambdaString = expression.Substring(expression.IndexOf("=>") + 2).Trim();
var paramList = paramString.Split(',');
if (paramList.Length != paramTypes.Length)
throw new ArgumentException("Specified number of lambda parameters do not match the number of parameter types!", "expression");
List<ParameterExpression> parameters = new List<ParameterExpression>();
for (int i = 0; i < paramList.Length; i++)
parameters.Add(Expression.Parameter(paramTypes[i], paramList[i].Trim()));
return ParseLambda(parameters.ToArray(), returnType, lambdaString, null);
}
Usage for both:
Func<string, string> func = DynamicExpression.ParseLambda<string, string>("f => f.Substring(0, f.IndexOf(\" \"))").Compile();
Func<string, int, string> otherFunc = ((Expression<Func<string, int, string>>)DynamicExpression.ParseLambda("(str, ind) => (ind * 100).ToString() + str")).Compile();
Edit: This has not been thoroughly tested, so you might want to make sure with some unit tests that these produce the correct results. I'm not doing anything overly complicated, just explicitly declaring the parameters to use in the public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
method.
Also fixed bug pointed out by @Mauro Destro by trimming the parameter name from paramList
when creating the ParameterExpression
.
You can use Roslyn scripting to do this. For example:
var str = "f => f.Substring(0, f.IndexOf(' '))";
var func = await CSharpScript.EvaluateAsync<Func<string, string>>(str);
var firstWord = func("Hello World");
This requires the Microsoft.CodeAnalysis.CSharp.Scripting
package.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With