I tried to compile and calculate LambdaExpression like:
Plus(10, Plus(1,2))
But result is 4, not 13.
Code:
using System;
using System.Linq.Expressions;
namespace CheckLambdaExpressionBug
{
class Program
{
static void Main(string[] _args)
{
ParameterExpression p1 = Expression.Parameter(typeof (int), "p1");
ParameterExpression p2 = Expression.Parameter(typeof (int), "p2");
LambdaExpression lambda = Expression.Lambda(Expression.Call(typeof(Program).GetMethod("Plus"), p1, p2), p1, p2);
InvocationExpression exp1 = Expression.Invoke(
lambda,
Expression.Constant(1),
Expression.Constant(2)
);
InvocationExpression exp2 = Expression.Invoke(
lambda,
Expression.Constant(10),
exp1
);
var func = (Func<int>) Expression.Lambda(exp2).Compile();
int v = func();
Console.Out.WriteLine("Result = {0}", v);
}
public static int Plus(int a, int b)
{
return a + b;
}
}
}
Since nobody seems to be posting this:
It looks to be a bug in .NET 3.5, and is fixed in .NET 4.
whereas this seems to produce 13 in 3.5 too:
var plus = new Func<int, int, int>((a, b) => a + b);
var func = new Func<int>(() => plus(10, plus(1, 2)));
var res = func();
Console.WriteLine(res);
maybe i needs to assign the result to a local var
try this
var plus = new Func((a, b) => a + b);
var puls_1 = plus(1, 2);
var func = new Func(() => plus(10, plus_1));
var res = func();
Console.WriteLine(res);
Related
I have two classes.
public class First
{
public int P {get; set;}
public int A {get; set;}
public int B {get; set;}
}
public class Second
{
public int P {get; set;}
public int C {get; set;}
}
I want to calculate something like this.
var first = A collection of First,
var second = A collection of Second
first.Select(f=> f.A * second.FirstOrDefault(s => s.P == f.P).C).Sum();
I can change f=> f.A in an expression using ()
ParameterExpression f = Expression.Parameter(typeof(First), 'f');
Expression a = Expression.Property(f, "A");
var lambda = Expression.Lambda(Func<First, decimal>(a, f));
lambda.Complie()
I tried to change s => s.P == f.P in an expression using // internal lambda
ParameterExpression f = Expression.Parameter(typeof(First), 'f');
ParameterExpression s = Expression.Parameter(typeof(Second), 's');
Expression fp = Expression.Property(f, "P");
Expression sp = Expression.Property(s, "P");
Expression finalExp = Expression.Equal(sp, fp);
var lambda = Expression.Lambda(Func<Second, bool>(finalExp , s));
lambda.Complie()
I faced two issues in this code.
Internal lambda code fails at lambda.Complie(). Error: - system linq expression variable 'f' of type 'First' referenced from scope '', but it is not defined.
In first.Select(f=> f.A * second.FirstOrDefault(s => s.P == f.P).C), f=> f.A is an expression and the other part is a decimal, so can't multiply.
Assuming that you need generic method for handling such expressions:
public static int CalcSum<TFirst, TSecond>(IEnumerable<TFirst> first, IEnumerable<TSecond> second)
{
var f = Expression.Parameter(typeof(TFirst), "f");
var s = Expression.Parameter(typeof(TSecond), "s");
var firstQueryable = first.AsQueryable();
var secondQueryable = second.AsQueryable();
// s => f.P == s.P
var firstOrDefaultFilter = Expression.Lambda(
Expression.Equal(Expression.Property(f, "P"), Expression.Property(s, "P")),
s);
// second.FirstOrDefault(f.P == s.P)
var firstOrDefault = Expression.Call(typeof(Queryable), nameof(Queryable.FirstOrDefault),
new[] { typeof(TSecond) }, secondQueryable.Expression, firstOrDefaultFilter);
// second.FirstOrDefault(f.P == s.P).C
var propertyToSum = Expression.Property(firstOrDefault, "C");
// f => f.A * second.FirstOrDefault(f.P == s.P).C
var selectLambda = Expression.Lambda(
Expression.Multiply(Expression.Property(f, "A"), propertyToSum),
f);
// first.Select(f => f.A * second.FirstOrDefault(f.P == s.P).C)
var queryExpr = Expression.Call(typeof(Queryable), nameof(Queryable.Select),
new Type[] { typeof(TFirst), typeof(int) }, firstQueryable.Expression, selectLambda);
var query = firstQueryable.Provider.CreateQuery<int>(queryExpr);
return query.Sum();
}
I have an object of any of the func types func<>, Func<,>, func<,,> ... And I'd like to replace one of the input parameters with a constant value.
eg:
object SetParameter<T>(object function, int index, T value){
//I don't know how to code this.
}
Func<int, String, String> function = (a, b) => a.ToString() + b;
object objectFunction = function;
object newFunction = SetParameter<int>(objectFunction, 0, 5);
// Here the new function should be a Func<String, String> which value "(b) => function(5, b)"
I already now how to get the type of the resulting function, but that does not really help me in implementing the desired behavior:
private Type GetNewFunctionType<T>(object originalFunction, int index, T value)
{
Type genericType = originalFunction.GetType();
if (genericType.IsGenericType)
{
var types = genericType.GetGenericArguments().ToList();
types.RemoveAt(index);
Type genericTypeDefinition = genericType.GetGenericTypeDefinition();
return genericTypeDefinition.MakeGenericType(types.ToArray());
}
throw new InvalidOperationException($"{nameof(originalFunction)} must be a generic type");
}
It's not quite clear what the purpose of your conversion is for, but wouldn't it be easier to avoid all the reflection. E.g.:
Func<int, string, string> func3 = (a, b) => a.ToString() + b;
Func<string, string> func3withConst = (b) => func3(10, b);
Since you are talking about a very limited scope (supporting just Func<TReturn>, Func<T1, TReturn> and Func<T1, T2, TReturn>) doing this through reflection is much more error prone and harder to read.
Just in case you need to use expression tree to build the function:
object SetParameter<T>(object function, int index, T value)
{
var parameterTypes = function.GetType().GetGenericArguments();
// Skip where i == index
var newFuncParameterTypes = parameterTypes.SkipWhile((_, i) => i == index).ToArray();
// Let's assume function is Fun<,,> to make this example simple :)
var newFuncType = typeof(Func<,>).MakeGenericType(newFuncParameterTypes);
// Now build a new function using expression tree.
var methodCallParameterTypes = parameterTypes.Reverse().Skip(1).Reverse().ToArray();
var methodCallParameters = methodCallParameterTypes.Select(
(t, i) => i == index
? (Expression)Expression.Constant(value, typeof(T))
: Expression.Parameter(t, "b")
).ToArray();
// func.Invoke(5, b)
var callFunction = Expression.Invoke(
Expression.Constant(function),
methodCallParameters);
// b => func.Invoke(5, b)
var newFunc = Expression.Lambda(
newFuncType,
callFunction,
methodCallParameters.OfType<ParameterExpression>()
).Compile();
return newFunc;
}
To use this:
Func<int, string, string> func = (a, b) => a.ToString() + b;
var newFunc = (Func<string, string>)SetParameter<int>(func, 0, 5);
// Output: 5b
Console.WriteLine(newFunc("b"));
For example I have some class with some property:
public class SomeClass
{
public Version Version { get; set; }
}
And I have a list of this type with sample data:
var list = new List<SomeClass>();
for (var i = 0; i < 1000; i++)
{
list.Add(new SomeClass
{
Version = new Version(i, i / 2, i / 3, i / 4),
});
}
I want to write method that filters by version using Version.Equals method:
var filterValue = new Version(12, 6, 4, 3);
var modelType = typeof(SomeClass);
var propertyType = typeof(Version);
var arg = Expression.Parameter(modelType, "x");
var property = Expression.Property(arg, "Version");
var value = Expression.Convert(Expression.Constant(filterValue), propertyType);
var versionEqualsMethod = typeof(Version).GetMethod("Equals", new[] { typeof(Version) });
/////////
Expression inst = null; // <-- ???
/////////
var expr = Expression.Call(inst, versionEqualsMethod, property, value);
var delegateType = typeof(Func<,>).MakeGenericType(modelType, typeof(bool));
var delegateValue = Expression.Lambda(delegateType, expr, arg).Compile();
var genericMethod =
typeof(Enumerable).GetMethods()
.First(
method =>
method.Name == "Where" && method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 1 && method.GetParameters().Length == 2)
.MakeGenericMethod(modelType);
var result = genericMethod.Invoke(null, new object[] { list, delegateValue });
What do I use as instance in Expression.Call?
UPDATE
Solution is:
var expr = Expression.Call(property, versionEqualsMethod, value);
You normally would do:
var filterValue = new Version(12, 6, 4, 3);
var modelType = typeof(SomeClass);
var propertyType = typeof(Version);
var arg = Expression.Parameter(modelType, "x");
var property = Expression.Property(arg, "Version");
// Changes from here onward
var value = Expression.Constant(filterValue);
var versionEqualsMethod = typeof(Version).GetMethod("Equals", new[] { typeof(Version) });
var expr = Expression.Call(property, versionEqualsMethod, value);
Because the Equals would be used like:
model.Version.Equals(filterValue);
I'm not handling the model.Version == null case!
Note that you don't need the Expression.Convert.
And what you are doing is ok if the "containing method" (the method where you'll put this code) is non-generic, but normally it would be a generic method, that has as the generic parameter the modelType, so the last part of the code would be different (starting from var delegateType =), because you could use the TModelType generic type directly.
Maybe I'm missing out on something, but wouldn't this work:
var results = list.Where(sc => sc.Version == filterVersion);
What you are trying to accomplish is much easier to do with reflection. Check this running online example. (If I understand you correctly that is... It would be helpful, if you could provide the signature of the function you are trying to write.)
Implementation
public static class Extensions
{
public static IEnumerable<T> Filter<T>(
this IEnumerable<T> enumerable, string propertyName, object filterValue)
{
var elementType = typeof (T);
var property = elementType.GetProperty(propertyName);
return enumerable.Where(element =>
{
var propertyValue = property.GetMethod.Invoke(element, new object[] {});
return propertyValue.Equals(filterValue);
});
}
}
Usage
var list = new List<SomeClass>();
for (var i = 0; i < 1000; i++)
{
list.Add(new SomeClass {Version = new Version(i, i/2, i/3, i/4)});
}
var filteredList = list.Filter("Version", new Version(12, 6, 4, 3));
Console.WriteLine(filteredList.Single().Version);
I've decided to take some golden time to learn a bit more about Expressions. I'm trying a very simple exercise, namely adding two numbers. I've hit an exception that's proving to be tricky to search for.
Here's my code
Expression<Func<int,int,int>> addExpr = (x, y) => x + y;
var p1 = Expression.Parameter(typeof(int), "p1");
var p2 = Expression.Parameter(typeof(int), "p2");
var lambda = Expression.Lambda<Func<int,int,int>>(addExpr, p1, p2); //<-here
var del = lambda.Compile();
var result = del(2,3); //expect 5
but this is throwing an ArgumentException : Expression of type 'System.Func`3[System.Int32,System.Int32,System.Int32]' cannot be used for return type 'System.Int32'
at the line indicated above. What have I done wrong?
You need to wrap the addExpr in an invoke using the expression parameters
Expression<Func<int,int,int>> addExpr = (x, y) => x + y;
var p1 = Expression.Parameter(typeof(int), "p1");
var p2 = Expression.Parameter(typeof(int), "p2");
var invokeExpression=Expression.Invoke(addExpr,p1,p2);
var lambda = Expression.Lambda<Func<int,int,int>>(invokeExpression,p1,p2);
var del = lambda.Compile();
var result=del(2,3);
The invoke is how you type p1 to x and p2 to y, alternatively you could just write the above as
var p1 = Expression.Parameter(typeof(int), "p1");
var p2 = Expression.Parameter(typeof(int), "p2");
var lambda=Expresion.Lambda<Func<int,int,int>>(Expression.Add(p1,p2),p1,p2);
var del = lambda.Compile();
var result=del(2,3);
Otherwise you need to grab the expression body into the lambda and pass the expression parameters.
var lambda=Expresion.Lambda<Func<int,int,int>>(addExpr.Body,addExpr.Parameters);
Your code should be:
var lambda = Expression.Lambda<Func<Expression<Func<int, int, int>>, int, int>(addExpr, p1, p2);
Your current code expects an int and your passing in Expression<Func<int, int, int>>.
Update
Actually the above won't compile, you would need to do:
var lambda = Expression.Lambda<Func<int, int, int>>(Expression.Add(p1, p2), p1, p2);
You need to decompose addExpr's body or preferably just write it from scratch ie Expression.Add(p1,p2) instead of addExpr.
is it possible to create an anonymous method in c# from a string?
e.g. if I have a string "x + y * z" is it possible to turn this into some sort of method/lambda object that I can call with arbitrary x,y,z parameters?
It's possible, yes. You have to parse the string and, for example, compile a delegate using expression trees.
Here's an example of creating (x, y, z) => x + y * z using expression trees:
ParameterExpression parameterX = Expression.Parameter(typeof(int), "x");
ParameterExpression parameterY = Expression.Parameter(typeof(int), "y");
ParameterExpression parameterZ = Expression.Parameter(typeof(int), "z");
Expression multiplyYZ = Expression.Multiply(parameterY, parameterZ);
Expression addXMultiplyYZ = Expression.Add(parameterX, multiplyYZ);
Func<int,int,int,int> f = Expression.Lambda<Func<int, int, int, int>>
(
addXMultiplyYZ,
parameterX,
parameterY,
parameterZ
).Compile();
Console.WriteLine(f(24, 6, 3)); // prints 42 to the console
Just for fun using CodeDom (any valid C# code is allowed in the string as long as it is present in mscorlib (No check for errors at all):
static class Program
{
static string code = #"
public static class __CompiledExpr__
{{
public static {0} Run({1})
{{
return {2};
}}
}}
";
static MethodInfo ToMethod(string expr, Type[] argTypes, string[] argNames, Type resultType)
{
StringBuilder argString = new StringBuilder();
for (int i = 0; i < argTypes.Length; i++)
{
if (i != 0) argString.Append(", ");
argString.AppendFormat("{0} {1}", argTypes[i].FullName, argNames[i]);
}
string finalCode = string.Format(code, resultType != null ? resultType.FullName : "void",
argString, expr);
var parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("mscorlib.dll");
parameters.ReferencedAssemblies.Add(Path.GetFileName(Assembly.GetExecutingAssembly().Location));
parameters.GenerateInMemory = true;
var c = new CSharpCodeProvider();
CompilerResults results = c.CompileAssemblyFromSource(parameters, finalCode);
var asm = results.CompiledAssembly;
var compiledType = asm.GetType("__CompiledExpr__");
return compiledType.GetMethod("Run");
}
static Action ToAction(this string expr)
{
var method = ToMethod(expr, new Type[0], new string[0], null);
return () => method.Invoke(null, new object[0]);
}
static Func<TResult> ToFunc<TResult>(this string expr)
{
var method = ToMethod(expr, new Type[0], new string[0], typeof(TResult));
return () => (TResult)method.Invoke(null, new object[0]);
}
static Func<T, TResult> ToFunc<T, TResult>(this string expr, string arg1Name)
{
var method = ToMethod(expr, new Type[] { typeof(T) }, new string[] { arg1Name }, typeof(TResult));
return (T arg1) => (TResult)method.Invoke(null, new object[] { arg1 });
}
static Func<T1, T2, TResult> ToFunc<T1, T2, TResult>(this string expr, string arg1Name, string arg2Name)
{
var method = ToMethod(expr, new Type[] { typeof(T1), typeof(T2) },
new string[] { arg1Name, arg2Name }, typeof(TResult));
return (T1 arg1, T2 arg2) => (TResult)method.Invoke(null, new object[] { arg1, arg2 });
}
static Func<T1, T2, T3, TResult> ToFunc<T1, T2, T3, TResult>(this string expr, string arg1Name, string arg2Name, string arg3Name)
{
var method = ToMethod(expr, new Type[] { typeof(T1), typeof(T2), typeof(T3) },
new string[] { arg1Name, arg2Name, arg3Name }, typeof(TResult));
return (T1 arg1, T2 arg2, T3 arg3) => (TResult)method.Invoke(null, new object[] { arg1, arg2, arg3 });
}
static void Main(string[] args)
{
var f = "x + y * z".ToFunc<int, int, long, long>("x", "y", "z");
var x = f(3, 6, 8);
}
}
C# doesn't have any functionality like this (other languages - like JavaScript - have eval functions to handle stuff like this). You will need to parse the string and create a method yourself with either expression trees or by emitting IL.
There are functionality to do this in the .Net framework.
It is not easy. You need to add some code around the statement to make it into a complete assembly including a class and method you can call.
After that you pass the string to
CSharpCodeProvider.CompileAssemblyFromSource(options, yourcode);
Here is an example
It could be possible with a grammar (e.g. ANTLR) and an interpreter which creates expression trees. This is no small task, however, you can be successful if you limit the scope of what you accept as input. Here are some references:
C# ANTLR3 Grammar (complex, but you could extract a portion)
Expression Trees
Here is what some code may look like to transform an ANTLR ITree into an Expression tree. It isn't complete, but shows you what you're up against.
private Dictionary<string, ParameterExpression> variables
= new Dictionary<string, ParameterExpression>();
public Expression Visit(ITree tree)
{
switch(tree.Type)
{
case MyParser.NUMBER_LITERAL:
{
float value;
var literal = tree.GetChild(0).Text;
if (!Single.TryParse(literal, out value))
throw new MyParserException("Invalid number literal");
return Expression.Constant(value);
}
case MyParser.IDENTIFIER:
{
var ident = tree.GetChild(0).Text;
if (!this.variables.ContainsKey(ident))
{
this.variables.Add(ident,
Expression.Parameter(typeof(float), ident));
}
return this.variables[ident];
}
case MyParser.ADD_EXPR:
return Expression.Add(Visit(tree.GetChild(0)), Visit(tree.GetChild(1)));
// ... more here
}
}