Rozwiązanie nr. 1 @czesiek jest praktyczne, czytelne i łatwe do zmiany, ale jest tak średnio dynamiczne
da się to uczynić bardziej dynamicznym, ale trzeba się trochę nakodzić oraz przemyśleć użycie.
W tym przypadku zrobiłem tak, że NazwaProperty
+ słówko "Operator" definiuje jaki ma być operator ma być użyty w lambdzie (>, <, ==, >= itd.)
public class User
{
public User(string firstName, bool isProfientAtJava, int PizzasPerMonth)
{
FirstName = firstName;
IsProfientAtJava = isProfientAtJava;
SalaryAsPizzasPerMonth = PizzasPerMonth;
}
public string FirstName { get; set; }
public bool IsProfientAtJava { get; set; }
public int SalaryAsPizzasPerMonth { get; set; }
}
public class SearchInput
{
public string FirstName { get; set; }
public string FirstNameOperator { get; set; }
public bool? IsProfientAtJava { get; set; }
public string IsProfientAtJavaOperator { get; set; }
public int? SalaryAsPizzasPerMonth { get; set; }
public string SalaryAsPizzasPerMonthOperator { get; set; }
}
private static Expression GetPredicateExpression(Expression param, string paramName, string operatorr, object value)
{
switch (operatorr)
{
case "Equal":
return Expression.Equal
(
Expression.Property(param, paramName),
Expression.Constant(value)
);
case "GreaterThan":
return Expression.GreaterThan
(
Expression.Property(param, paramName),
Expression.Constant(value)
);
default:
throw new Exception("invalid operator");
}
}
public static Func<User, bool> ObtainLambda(string paramName, object value, string operatorr)
{
var param = Expression.Parameter(typeof(User), "p");
var expression = GetPredicateExpression(param, paramName, operatorr, value);
var exp = Expression.Lambda<Func<User, bool>>
(
expression,
param
);
return exp.Compile();
}
I tutaj użycie: wyciągnij Tomów, którzy zarabiają > 30
var searchInput = new SearchInput
{
FirstName = "Tom",
FirstNameOperator = "Equal",
SalaryAsPizzasPerMonth = 30,
SalaryAsPizzasPerMonthOperator = "GreaterThan"
};
var users = new List<User>
{
new User("Tom", true, 25),
new User("NotTom", true, 40),
new User("Tom", true, 70),
new User("Test", false, 31),
new User("Tom", false, 31),
new User("Tom", true, 30),
};
var query = users;
var properties = searchInput.GetType().GetProperties();
foreach (PropertyInfo propertyInfo in properties.Where(x => x.GetValue(searchInput) != null && !x.Name.Contains("Operator")))
{
var name = propertyInfo.Name;
var value = propertyInfo.GetValue(searchInput);
var operatorr = properties.FirstOrDefault(x => x.Name == $"{name}Operator")?.GetValue(searchInput)?.ToString() ?? "operator not found";
var avaliableOperators = new[] { "Equal", "GreaterThan" };
if (!avaliableOperators.Contains(operatorr))
throw new Exception($"operator '{operatorr}' is not supported.");
query = query.Where(ObtainLambda(name, value, operatorr)).ToList();
}
foreach (var user in query)
{
Console.WriteLine(user.FirstName);
Console.WriteLine(user.IsProfientAtJava);
Console.WriteLine(user.SalaryAsPizzasPerMonth);
Console.WriteLine();
}
Wynik:
Tom
True
70
Tom
False
31
Lub
var searchInput = new SearchInput
{
IsProfientAtJava = false,
IsProfientAtJavaOperator = "Equal"
};
Wynik:
Test
False
31
Tom
False
31