Bilgehan
Bilgehan

Reputation: 1227

Prepare Dynamic Lambda Expression with Checking parentproperty null control

I have dynamic lambda expression tree,I prepare my expression and compile it.

My problem is when I prepare expression something like

MyClass1.Property2.ChildProperty1=="xyz";

if Property2 is null then I take nullrefence error.

public class MyClass1
{
    public string Property1{get;set;}
    public MyClass2 Property2{get;set;}
}

public class MyClass2
{
    public string ChildProperty1{get;set;}
    public string ChildProperty2{get;set;}
}

public Func<T, bool> CompileRule<T>(Rule r)
{
     ...
     Func<T, bool> myfunc =Expression.Lambda<Func<T, bool>>(expr, paramUser).Compile();
     ...
     return myfunc;
}

Another function I execute my request like " myfunc(myrequest); "

Is there a generic way to check null control when I preprare my expression in CompileTime,If ParentProperty null then return false for these statement?In compile method I dont have entity ,so I have to prepare statement with check null control

Upvotes: 1

Views: 1056

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205629

So you want to create dynamically a body of an expression like this:

Expression<Func<MyClass1, string>> expr = 
    x => x.Property2?.ChildProperty1;

Unfortunately currently there is not standard Expression method supporting that. If you try the above, you'll get a compile time error:

Error CS8072 An expression tree lambda may not contain a null propagating operator.

One possible way is to generate a body of an expression like this instead:

Expression<Func<MyClass1, string>> expr = 
    x => x.Property2 != null ? x.Property2.ChildProperty1 : null;

It's not the exact equivalent, but should work.

Here is a sample snippet which does that dynamically:

string memberPath = ...; // e.g. "Property2.ChildProperty2"
var parameter = Expression.Parameter(typeof(T), "x");
Expression result;
if (memberPath.IndexOf('.') < 0)
    result = Expression.PropertyOrField(parameter, memberPath);
else
{
    var memberNames = memberPath.Split('.');
    var members = new Expression[memberNames.Length];
    for (int i = 0; i < memberNames.Length; i++)
        members[i] = Expression.PropertyOrField(i > 0 ? members[i - 1] : parameter, memberNames[i]);
    result = members[members.Length - 1];
    // For non nullable value types, promote the result into the corresponding nullable type
    if (result.Type.IsValueType && Nullable.GetUnderlyingType(result.Type) == null)
        result = Expression.Convert(result, typeof(Nullable<>).MakeGenericType(result.Type));
    var nullResult = Expression.Constant(null, result.Type);
    for (int i = members.Length - 2; i >= 0; i--)
    {
        result = Expression.Condition(
            Expression.NotEqual(members[i], Expression.Constant(null)),
            result, nullResult);
    }
}

At the end, the result variable contains the expression that you can use for left side of the comparison predicate.

Upvotes: 2

Related Questions