using System;
using System.Linq;
public abstract class Predicate {
public static Func<T, bool> ToFunc<T>(Predicate p) {
if (p is ConstPredicate) {
var p_ = p as ConstPredicate;
return (x) => p_.Value;
}
if (p is PropertyPredicate) {
var p_ = p as PropertyPredicate;
var property = typeof(T).GetProperty(p_.Name);
return (x) => (bool)property.GetValue(x);
}
if (p is AndPredicate) {
var p_ = p as AndPredicate;
var a = ToFunc<T>(p_.A);
var b = ToFunc<T>(p_.B);
return (x) => a(x) && b(x);
}
throw new Exception("Unsupported predicate type");
}
public static string ToSQL(Predicate p) {
if (p is ConstPredicate) {
var p_ = p as ConstPredicate;
return p_.Value ? "true" : "false";
}
if (p is PropertyPredicate) {
var p_ = p as PropertyPredicate;
return p_.Name;
}
if (p is AndPredicate) {
var p_ = p as AndPredicate;
return "(" + ToSQL(p_.A) + ") AND (" + ToSQL(p_.B) + ")";
}
throw new Exception("Unsupported predicate type");
}
}
public sealed class ConstPredicate : Predicate {
public bool Value { get; }
public ConstPredicate(bool value) {
Value = value;
}
}
public sealed class PropertyPredicate : Predicate {
public string Name { get; }
public PropertyPredicate(string name) {
Name = name;
}
}
public sealed class AndPredicate : Predicate {
public Predicate A { get; }
public Predicate B { get; }
public AndPredicate(Predicate a, Predicate b) {
A = a;
B = b;
}
}
public static class Program {
public sealed class Person {
public bool Alive { get; }
public Person(bool alive) {
Alive = alive;
}
}
public static void Main() {
var predicate = new AndPredicate(
new ConstPredicate(true),
new PropertyPredicate(nameof(Person.Alive))
);
var people = new[] {
new Person(alive: true),
new Person(alive: false),
};
foreach (var person in people.Where(Predicate.ToFunc<Person>(predicate))) {
Console.WriteLine(person.Alive);
}
Console.WriteLine(Predicate.ToSQL(predicate));
}
}