Can I write this
return (a, b) => (b == 0) ? 0: a / b;
With an if-else to the right of (a, b) =>
If you are returning a Func<double, double, double> it could be re-written as
return (a, b) =>
{
if(b == 0)
return 0;
else
return a / b;
};
If you are returning a Expression<Func<double, double, double>> it is not very easy to do, you will need to create a custom Expression by hand to represent the statement as there is no way to represent it in C#.
Have not tested it, but I think the Expression version would be
public Expression<Func<double, double, double>> IThinkThisWorks()
{
var paramA = Expression.Parameter(typeof(double), "a");
var paramB = Expression.Parameter(typeof(double), "b");
var const0 = Expression.Constant(0.0);
var test = Expression.Equal(paramA, paramB);
var division = Expression.Divide(paramA, paramB);
var ifCheck = Expression.IfThenElse(test, const0, division);
return Expression.Lambda<Func<double, double, double>>(ifCheck, paramA, paramB);
}
Related
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"));
Can we simplify the following with ?? and lambda expression?
Func<int, int> func = f; // f is a function parameter
if (func == null) // if f passed by the user is null then we use the default identity function f(x)=x.
func = x => x;
I cannot do something Func<int, int> func = f ?? x=>x;. Could you?
Edit
My scenario is as follows.
class Program
{
static double Average(int[] data, Func<int, int> f = null)
{
int sum = 0;
Func<int, int> func = f ?? new Func<int, int>(x => x);
//Func<int, int> func = f;
//if (func == null)
// func = x => x;
foreach (int x in data)
sum += func(x);
return (double)sum / data.Length;
}
static void Main(string[] args)
{
int[] data = { 1, 2, 3 };
Console.WriteLine(Average(data));
}
}
The precedence of null-coalescing operator is higher than lambda declaration.
Func<int, int> func = f ?? (x => x);
Possible duplicate of Null-coalescing operator and lambda expression
This should work
Func<int, int> func = f ?? (x=>x);
Your statement is parsed as
Func<int, int> func = (f ?? x)=>x;
Please search through the available answers first to check if somebody has already answered it.
how can I add an extra parameter to my Func<> expression ? Something like:
Func<char, bool> myPredicate = (x) => (char.IsLetter(x) || x == 'X');
...
"abc".All(x => char.IsDigit(x) || myPredicate);
but I get an error
Operator '||' cannot be applied to operands of type 'bool' and Func< char, bool>
You need to invoke the myPredicate function like this:
"abc".All(x => char.IsDigit(x) || myPredicate(x));
Or, what about this other approach?
var text = "abc";
var predicates = new Func<char, bool>[] {
x => char.IsLetter(x) || x == 'X',
char.IsDigit
};
var result = predicates.Any(text.All);
// Outputs TRUE
Console.WriteLine(result);
Also, if you need to check many specific characters, you can create a charEquals with curried parameters:
var text = "abc";
// More type inference to generalize charEquals to just equals, please!
Func<char, Func<char, bool>> charEquals = ca => cb => ca == cb;
var predicates = new Func<char, bool>[] {
char.IsLetter,
charEquals('X'),
charEquals('Y'),
charEquals('Z'),
char.IsDigit
};
var result = predicates.Any(text.All);
Console.WriteLine(result);
I have my custom Visitor which looks to right and left and changes parameters to constant.
I know that just change node is not possible.
I should return new lambda expression which contains constants instead parameters.
But I can not create an expression myself :(
I have this code:
public class ParametersTransformToConstantVisitor : ExpressionVisitor
{
private Dictionary<string, ConstantExpression> parameters = new Dictionary<string, ConstantExpression>();
public ParametersTransformToConstantVisitor(Dictionary<string, ConstantExpression> parameters)
{
this.parameters = parameters;
}
protected override Expression VisitBinary(BinaryExpression node)
{
var constExprLeftName = new Lazy<string>(() => ((ParameterExpression) node.Left)?.Name);
var constExprRightName = new Lazy<string>(() => ((ParameterExpression) node.Right)?.Name);
var constExprName = new Lazy<string>(() => ((ParameterExpression) node.Reduce())?.Name);
ParameterExpression leftParam = null;
ParameterExpression rightParam = null;
if (node.NodeType == ExpressionType.Parameter && parameters.ContainsKey(constExprName.Value))
{
return parameters[constExprName.Value];
}
if (node.Left.NodeType == ExpressionType.Parameter && parameters.ContainsKey(constExprLeftName.Value))
{
leftParam = (ParameterExpression) node.Left;
}
if (node.Right.NodeType == ExpressionType.Parameter && parameters.ContainsKey(constExprLeftName.Value))
{
rightParam = (ParameterExpression) node.Right;
}
if (leftParam != null || rightParam != null)
{
//return Expression.Lambda();
}
return base.VisitBinary(node);
}
}
Help me to build lambda expression, please
It feels like all you actually need here is:
protected override Expression VisitParameter(ParameterExpression node)
=> parameters.TryGetValue(node.Name, out var ce) ? (Expression)ce : node;
protected override Expression VisitLambda<T>(Expression<T> node)
=> Expression.Lambda(Visit(node.Body), node.Parameters); // don't visit the parameters
i.e. whenever the visitor sees a ParameterExpression, if there is a corresponding item in the parameters map, use that value.
The override on VisitLambda is because VisitLambda still needs to return a lambda of the same shape, and the default implementation would also visit (and thus swap) out the parameters from the declaration.
It is the visitor's job to worry about reassembling the tree around your changes.
Note, however, that if you are trying to create a parameterless lambda, you might also need to rewrite the root. Or you could just use the .Body and forget about the parameters.
Example:
Expression<Func<int, int, string>> add = (x, y) => ((2 * x) + y).ToString();
Console.WriteLine(add);
var args = new Dictionary<string, ConstantExpression>
{
["x"] = Expression.Constant(4),
["y"] = Expression.Constant(1),
};
var visitor = new ParametersTransformToConstantVisitor(args);
var result = (LambdaExpression)visitor.Visit(add);
Console.WriteLine(result);
which gives:
(x, y) => ((2 * x) + y).ToString()
(x, y) => ((2 * 4) + 1).ToString()
You can make this into a parameterless lambda via:
var withoutArgs = Expression.Lambda<Func<string>>(result.Body);
Console.WriteLine(withoutArgs);
which gives:
() => ((2 * 4) + 1).ToString()
minor addition: you might also want to simplify in the visitor:
protected override Expression VisitBinary(BinaryExpression node)
{
var visited = base.VisitBinary(node);
if(visited is BinaryExpression be
&& be.Method == null && be.Conversion == null
&& !be.IsLifted
&& be.Left is ConstantExpression left
&& be.Right is ConstantExpression right)
{
object val;
switch(be.NodeType)
{
case ExpressionType.Add:
val = (dynamic)left.Value + (dynamic)right.Value;
break;
case ExpressionType.Multiply:
val = (dynamic)left.Value * (dynamic)right.Value;
break;
case ExpressionType.Subtract:
val = (dynamic)left.Value - (dynamic)right.Value;
break;
case ExpressionType.Divide:
val = (dynamic)left.Value / (dynamic)right.Value;
break;
default:
return visited; // unknown
}
return Expression.Constant(
Convert.ChangeType(val, visited.Type), visited.Type);
}
return visited;
}
This changes the outputs to:
(x, y) => ((2 * x) + y).ToString()
(x, y) => 9.ToString()
() => 9.ToString()
and we could possibly also even hoist the ToString()!
protected override Expression VisitMethodCall(MethodCallExpression node)
{
var visited = base.VisitMethodCall(node);
if (visited is MethodCallExpression mce)
{
if ((mce.Object == null || mce.Object is ConstantExpression)
&& mce.Arguments.All(x => x is ConstantExpression))
{
var obj = (mce.Object as ConstantExpression)?.Value;
var args = mce.Arguments.Select(x => ((ConstantExpression)x).Value).ToArray();
var result = mce.Method.Invoke(obj, args);
return Expression.Constant(result, mce.Type);
}
}
return visited;
}
which now gives us:
(x, y) => ((2 * x) + y).ToString()
(x, y) => "9"
() => "9"
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);