1

I'm trying to implement class that defines filter, to make it more explicit when it will be passed as argument to methods in my repository class (EF).

And I have a problem with definition of implicit operator from Expression to my class. Is it possible to make implementation for syntax near fd4 variable?

public class FilterDefinition<TEntity>
    where TEntity : class
{
    public FilterDefinition() { }

    public FilterDefinition(Expression<Func<TEntity, bool>> filter)
    {
        this.Filter = filter;
    }

    public virtual Expression<Func<TEntity, bool>> Filter { get; set; }

    public static implicit operator FilterDefinition<TEntity>(Expression<Func<TEntity, bool>> filter) => new FilterDefinition<TEntity>(filter);
}

public class SomeEntity
{
    public bool SomeBool { get; set; }
}

class Program
{
    static void Main()
    {
        FilterDefinition<SomeEntity> fd1 = new FilterDefinition<SomeEntity>(x => x.SomeBool);
        FilterDefinition<SomeEntity> fd2 = new FilterDefinition<SomeEntity> { Filter = x => x.SomeBool };
        FilterDefinition<SomeEntity> fd3 = (Expression<Func<SomeEntity, bool>>)(x => x.SomeBool);
        //FilterDefinition<SomeEntity> fd4 = x => x.SomeBool;

        Console.ReadKey();
    }
}

The purpose of FilterDefinition class was to pass as argument to generic repository of queries. And using inheritance define commonly used filters.

public class Repository<TEntity> : IRepository<TEntity>
    where TEntity : class
{
    private readonly DbSet<TEntity> dbSet;

    public Repository(DbContext context)
    {
        this.dbSet = context.Set<TEntity>();
    }

    public async Task<IEnumerable<TEntity>> GetAsync(
        FilterDefinition<TEntity> filter = null,
        OrderDefinition<TEntity> order = null,
        PagingDefinition paging = null)
    {
        return await new QueryBuilder<TEntity>(this.dbSet)
            .ApplyFilter(filter)
            .ApplyOrder(order)
            .ApplyPaging(paging)
            .ToQuery()
            .ToListAsync();
    }
PiotrZ
  • 13
  • 3
  • Please post your code as _text_, not an image. And no, I don't think this can be done. This _might_ be an XY problem. What is `FilterDefinition` for anyway? – Sweeper Feb 14 '20 at 07:19
  • 1
    You can't do it for the same reasons why you can't assign a lambda to a `var`. See https://stackoverflow.com/q/4965576/11683, https://stackoverflow.com/q/2687942/11683 and https://stackoverflow.com/q/411579/11683. – GSerg Feb 14 '20 at 07:47

1 Answers1

3

The short answer would be "not in this scenario", because syntactically, in fd4 you're not actually casting from an Expression[...] to your type. The compiler doesn't know that the lambda represents an Expression[...] until it knows what it is trying to do with the value; a lambda (x => x.SomeBool) can be interpreted as a wide range of both expression-tree types and delegate types (for anonymous methods), and the compiler here would not understand that you mean "treat the lambda as an Expression<Func<SomeEntity, bool>>, then use the implicit conversion operator to change the expression to a FilterDefinition". It simply can't (and doesn't) make that leap. You can get close, as with your fd3 example, but... a large part of me is wondering what FilterDefinition actually does here, because to an outside observer it doesn't really seem to add anything over the raw expression tree.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • The purpose of FilterDefinition class was to pass as argument to generic repository of queries. And using inheritance define commonly used filters. – PiotrZ Feb 14 '20 at 09:56