Expression tree - how to check if element of a list fulfills specific conditions?

42 Views Asked by At

I'm using an Expression<Func<T, object?>> DatabaseProjection which defines what values I want to extract from T. In specific case, I will get a list of objects (string or int):

DatabaseProjection = p => p.Voyages.SelectMany(v => v.Passages.Select(p => p.Location.Name))

Then, I pass some value, which must be used to check if any of the elements in the retrived list fulfills a condition. Condition is got from a method:

private static Expression GetExpression
    (ConditionType conditionType, InvocationExpression invokedProjection, ConstantExpression value) => conditionType switch
    {
        ConditionType.Is => Expression.Equal(invokedProjection, value),
        _ => throw new NotImplementedException($"{conditionType} is not supported."),
    };

This is the method that should build an expression on the list:

public static Expression CreateExpression(Condition condition, Expression projection, ParameterExpression parameter)
{
    var invokedProjection = Expression.Invoke(projection, parameter);

    //ConstantExpression value;
    if (invokedProjection.Type.GetInterfaces().Contains(typeof(IList)))
    {
        var containsMethod = typeof(IList).GetMethod("Contains", new Type[] { typeof(IList) });

        var genericType = invokedProjection.Type.GetTypeInfo().GetGenericArguments().First();
        var castValue = string.IsNullOrWhiteSpace(condition.Value) && genericType.IsValueType
            ? Activator.CreateInstance(genericType)
            : Convert.ChangeType(condition.Value, genericType);

        var value = Expression.Constant(castValue, genericType);

        var contExp = Expression.Call(containsMethod!, invokedProjection, GetExpression(condition.Type, **invokedProjection**, value));

        return Expression.Constant(false);
    }
}

I kno, that invokedProjection cannot be passed to GetProjection method because it's not possible to compare value (which is string type) to a list of strings. But I'm out of ideas what could be done here. In general, I must do something like LINQ:

list.Contains(el => el.Name == name)

The inner part is done in GetProjection, but how to make the iteration over the "list" to check the conditions for each of element?

Here is a call of CreateExpression method:

private static Expression CreateFilterExpression(Alert alert, ParameterExpression parameter, Func<string, Expression> createProjection)
{
    var conditionExpression = ExpressionFactory.CreateExpression(condition, projectionExpression, parameter);
        return expression;
}

That's an invokedExpression: invokedExpression which stores expression to get a list of names

0

There are 0 best solutions below