See sample code below. How can I modify it to handle null values, similar to how the ?.
operator works?
class Program
{
static LambdaExpression GetExpression(Expression<Func<string, string>> expr)
{
return expr;
}
static void Main(string[] args)
{
// I want to perform the following null propagation check
// in the expression tree below.
// (s as string)?.Replace("a", "o");
var expr = GetExpression(t => t);
var oldValue = Expression.Constant("a", typeof(string));
var newValue = Expression.Constant("o", typeof(string));
var mi = typeof(string).GetMethod(nameof(string.Replace), new[] { typeof(string), typeof(string) });
var invoke = Expression.Invoke(expr, expr.Parameters);
var call = Expression.Call(invoke, mi, oldValue, newValue);
var lambda = Expression.Lambda(call, false, expr.Parameters);
Console.WriteLine(lambda.Compile().DynamicInvoke("gaga"));
// Should print empty line. Not throw!
Console.WriteLine(lambda.Compile().DynamicInvoke(null));
}
}
You have to do 2 things:
The call lambda.Compile().DynamicInvoke(null)
is wrong.
The documentation states that the parameter can be:
Type: System.Object[]:
An array of objects that are the arguments to pass to the method represented by the current delegate.
-or-
null, if the method represented by the current delegate does not require arguments.
So, by passing null you invoke it without parameters, but you would like to invoke with a null string parameter:
This is why you should change this line to lambda.Compile().DynamicInvoke(new object[] {null})
or simply lambda.Compile().DynamicInvoke((string)null)
You have to add a null condition with Expression.Condition
.
The final code:
var expr = GetExpression(t => t);
var oldValue = Expression.Constant("a", typeof(string));
var newValue = Expression.Constant("o", typeof(string));
var mi = typeof(string).GetMethod(nameof(string.Replace), new[] { typeof(string), typeof(string) });
var invoke = Expression.Invoke(expr, expr.Parameters);
var call = Expression.Call(invoke, mi, oldValue, newValue);
ConstantExpression nullConst = Expression.Constant(null, typeof(string));
var nullCondition = Expression.Condition(Expression.Equal(invoke, nullConst),
nullConst, call);
var lambda = Expression.Lambda(nullCondition, false, expr.Parameters);
object result1 = lambda.Compile().DynamicInvoke("gaga"); // =="gogo"
object result2 = lambda.Compile().DynamicInvoke((string) null); //== null