using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
public int no { get; set; }
public string engine { get; set; }
public string model { get; set; }
public string color { get; set; }
public string country { get; set; }
public static class ExpressionExtensions
public static Expression<Func<T,bool>> AndAlsoAll<T>(this Expression<Func<T,bool>> expression, params Expression<Func<T,bool>> [] others)
var body = expression.Body;
var parameter = expression.Parameters[0];
foreach (var other in others)
body = Expression.AndAlso(body, new ParameterReplacer((other.Parameters[0], (Expression)parameter)).Visit(other.Body));
return Expression.Lambda<Func<T, bool>>(body, parameter);
class ParameterReplacer : ExpressionVisitor
readonly Dictionary<ParameterExpression, Expression> parametersToReplace;
public ParameterReplacer(params (ParameterExpression parameter, Expression replacement) [] parametersToReplace) =>
this.parametersToReplace = parametersToReplace.ToDictionary(p => p.parameter, p => p.replacement);
protected override Expression VisitParameter(ParameterExpression p) =>
parametersToReplace.TryGetValue(p, out var e) ? e : base.VisitParameter(p);
class MockupRepository<T>
IQueryable<T> db { get; }
public MockupRepository(IQueryable<T> db) => this.db = db;
public Task<IEnumerable<T>> ReadDocumentsWhereAll(Expression<Func<T,bool>> predicate, params Expression<Func<T,bool>> [] andAlsoAllPredicates)
return ReadDocuments(predicate.AndAlsoAll(andAlsoAllPredicates));
public Task<IEnumerable<T>> ReadDocuments(Expression<Func<T,bool>> predicate)
IEnumerable<T> result = db.Where(predicate);
return Task.FromResult(result);
MockupRepository<Car> carRepository = new (
new() { no = 101, engine = "gas", model = "studebaker", color = "mauve", country = "foo" },
new() { no = 201, engine = "gas", model = "DeLorean", color = "stainless steel", country = "foo" },
public async Task TestQuery()
var model = "studebaker";
var cars1 = await this.carRepository.ReadDocuments(car => car.no == no &&
car.engine == engine && car.model == model && car.color == color && car.country==country);
var cars = await this.carRepository.ReadDocumentsWhereAll(car => car.no == no,
car => car.engine == engine,
car => car.model == model,
car => car.color == color,
car => car.country==country);
Assert.That(JsonSerializer.Serialize(cars1) == JsonSerializer.Serialize(cars));
public void TestAndAlsoAll()
var model = "studebaker";
Expression<Func<Car,bool>> original =
car => car.no == no && car.engine == engine && car.model == model && car.color == color && car.country==country;
var combined = ExpressionExtensions.AndAlsoAll<Car>(
x => x.engine == engine, car => car.model == model, car => car.color == color, car => car.country==country);
Console.WriteLine(combined);
Assert.That(combined.ToString() == original.ToString());
public static async Task Main(string[] args)
Console.WriteLine("Environment version: {0} ({1}), {2}.\n", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
new TestClass().TestAndAlsoAll();
await new TestClass().TestQuery();