Search code examples
c#expression-trees

How to extend existing KeySelector


public class Address 
{
    public string City { get; set; }
    public string Street { get; set; }
}

public class User 
{
    public Address Address1 { get; set; }
    public Address Address2 { get; set; }
}

public class DefaultAddressSortingSpecification<TEntity>
{
    private readonly Expression<Func<TEntity, Address>> _keySelector;

    public DefaultAddressSortingSpecification(Expression<Func<TEntity, Address>> keySelector)
    {
        _keySelector = keySelector;
    }

    public IQueryable<TEntity> OrderingEntitiesFrom(IQueryable<TEntity> query)
    {
        //order by city
        //order by street
    }
}

usage: 

var s1 = new DefaultAddressSortingSpecification<User>(user => user.Address1);
var s2 = new DefaultAddressSortingSpecification<User>(user => user.Address2);

I would like to have universal AddressSortingSpecification. _keySelector points to Address entity. How to add City or Street to it?

Normally I can write something like this: user.Address1.City


Solution

  • As I understand the question, you want to know how to create expressions to access the City and Street properties of an Address when given an expression which only references an Address. Here's how I would do it:

    public IQueryable<TEntity> OrderingEntitiesFrom(IQueryable<TEntity> query)
    {
        var parameter = _keySelector.Parameters.Single();
    
        var address = _keySelector.Body;
    
        var citySelector = Expression.Lambda<Func<TEntity, string>>(Expression.Property(address, "City"), parameter);
        var streetSelector = Expression.Lambda<Func<TEntity, string>>(Expression.Property(address, "Street"), parameter);
    
        return query.OrderBy(citySelector).ThenBy(streetSelector);
    }