scottksmith95 / LINQKit

LINQKit is a free set of extensions for LINQ to SQL and Entity Framework power users.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

No support for `Expression.Default`

NiJeTi opened this issue · comments

I have a class with complex expression tree building method which utilizes Expression.Default under the hood.

public Expression<Func<TEntity, bool>> Build<TEntity, TValue>(
    ExtractionModel<TValue> extractionModel,
    Expression<Func<TEntity, TValue?>> propertySelector)
    where TEntity : class, IAuditedEntity
    where TValue : struct
{
    var expression = PredicateBuilder.New<TEntity>(true);

    if (extractionModel?.Include?.Any() is not true && extractionModel?.Exclude?.Any() is not true)
    {
        return expression;
    }

    if (extractionModel.Include?.Any() is true)
    {
        var filterExpression = BuildInternal(extractionModel.Include, propertySelector, true);
        expression = expression.And(filterExpression);
    }

    if (extractionModel.Exclude?.Any() is true)
    {
        var filterExpression = BuildInternal(extractionModel.Exclude, propertySelector, false);
        expression = expression.And(filterExpression);
    }

    return expression;
}

private static Expression<Func<TEntity, bool>> BuildInternal<TEntity, TValue>(
    HashSet<TValue> extractionCollection,
    Expression<Func<TEntity, TValue?>> propertySelector,
    bool positiveCheck)
    where TEntity : IAuditedEntity
    where TValue : struct
{
    var propertyType = typeof(TValue?);

    var valueProperty = propertyType.GetProperty(nameof(Nullable<TValue>.Value))!;
    var valueExpression = Expression.Property(propertySelector.Body, valueProperty);

    // var valueExistsExpression = Expression.NotEqual(propertySelector.Body, Expression.Default(propertyType));
    var valueExistsExpression = Expression.NotEqual(propertySelector.Body, Expression.Constant(default(TValue?)));

    var closure = new { Value = extractionCollection };
    var closureExpression = Expression.Property(Expression.Constant(closure), nameof(closure.Value));

    var containsExpression = Expression.Call(closureExpression, "Contains", Type.EmptyTypes, valueExpression);

    var andExpression = positiveCheck
        ? Expression.AndAlso(valueExistsExpression, containsExpression)
        : Expression.AndAlso(valueExistsExpression, Expression.Not(containsExpression));

    return Expression.Lambda<Func<TEntity, bool>>(andExpression, propertySelector.Parameters.First());
}

After this method invocation ExpressionVisitor throws an exception stating: Unhandled expression type: 'Default'

The most interesting part of it is that the first method call and combining the expressions works perfectly fine, but on the second call it throws exception mentioned before.

Is it possible for you to try the code in #182? I guess it should work for you

Closing this one because this issue is addressed by #182