如何根据输入参数条件动态创建“OR”LINQ查询

mtb9vblg  于 2024-01-03  发布在  其他
关注(0)|答案(2)|浏览(191)

我的问题有点复杂,所以我用下面的例子简化了它。
假设我有一个简单的整数列表。我在函数中接收两个条件输入参数,它们告诉我如何过滤。类似这样:

  1. public class input{
  2. public string operation = "less than";//can be <=, >=, !=, ==,<. >, etc.
  3. public integer filter = 9;
  4. }

字符串
我想根据传入的条件进行动态过滤,但我需要将其作为“OR”子句。
如何动态地创建一个linq查询,而不像这样对每个组合进行硬编码:

  1. /*
  2. input one = { operation = "less than" , filter = 9 }
  3. input two = { operation = "equal to", filter =10 }
  4. arraytoFilter { 1,2,3,4,5,6,7,8,9,10,11,12 }
  5. */
  6. public int[] myFilter(input one, input two, int[] arraytoFilter){
  7. if (one.operation == "less than" && two.operation == "equal to"){
  8. return arraytoFilter.Where(x => x < one.filter || x == two.filter)
  9. }
  10. if (one.operation == "less than or equal to" && two.operation == "greater than"){
  11. return arraytoFilter.Where(x => x <= one.filter || x > two.filter)
  12. }
  13. /// rest of all combinations (how do I avoid doing this???)
  14. return arrayToFilter;
  15. }

2exbekwf

2exbekwf1#

[更新11/20 ]
这可以在没有NuGet包的情况下通过使用System.Linq.Expressions构建表达式来完成:

  1. using System.Linq.Expressions;
  2. class Program
  3. {
  4. public class input
  5. {
  6. public string? operation { get; set; }
  7. public int filter { get; set; }
  8. }
  9. static void Main()
  10. {
  11. int[] arrayToFilter = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
  12. input one = new()
  13. {
  14. operation = "less than",
  15. filter = 9
  16. };
  17. input two = new()
  18. {
  19. operation = "equal to",
  20. filter = 10
  21. };
  22. var filteredArray = myFilter(one, two, arrayToFilter);
  23. foreach (var number in filteredArray)
  24. {
  25. Console.WriteLine(number);
  26. }
  27. }
  28. static int[] myFilter(input one, input two, int[] arrayToFilter)
  29. {
  30. var parameter = Expression.Parameter(typeof(int), "num");
  31. var firstComparisonExpression = GetComparisonExpression(parameter, one.operation, one.filter);
  32. var secondComparisonExpression = GetComparisonExpression(parameter, two.operation, two.filter);
  33. // Short-circuiting OR
  34. var orElseExpression = Expression.OrElse(firstComparisonExpression, secondComparisonExpression);
  35. var lambda = Expression.Lambda<Func<int, bool>>(orElseExpression, parameter);
  36. return arrayToFilter.AsQueryable().Where(lambda.Compile()).ToArray();
  37. }
  38. static Expression GetComparisonExpression(ParameterExpression parameter, string? operation, int filter)
  39. {
  40. switch (operation)
  41. {
  42. case "less than":
  43. return Expression.LessThan(parameter, Expression.Constant(filter));
  44. case "less than or equal to":
  45. return Expression.LessThanOrEqual(parameter, Expression.Constant(filter));
  46. case "greater than":
  47. return Expression.GreaterThan(parameter, Expression.Constant(filter));
  48. case "greater than or equal to":
  49. return Expression.GreaterThanOrEqual(parameter, Expression.Constant(filter));
  50. case "equal to":
  51. return Expression.Equal(parameter, Expression.Constant(filter));
  52. case "not equal to":
  53. return Expression.NotEqual(parameter, Expression.Constant(filter));
  54. default:
  55. throw new ArgumentException("Invalid operation phrase.");
  56. }
  57. }
  58. }

字符串
您可以使用System.Linq.Dynamic.Core包来编写动态LINQ查询。下面的程序已在1.3.5版本中测试:

  1. using System.Linq.Dynamic.Core;
  2. class Program
  3. {
  4. public class input
  5. {
  6. public string? operation { get; set; }
  7. public int filter { get; set; }
  8. }
  9. static void Main()
  10. {
  11. int[] arrayToFilter = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
  12. input one = new()
  13. {
  14. operation = "less than",
  15. filter = 9
  16. };
  17. input two = new()
  18. {
  19. operation = "equal to",
  20. filter = 10
  21. };
  22. var filteredArray = myFilter(one, two, arrayToFilter);
  23. foreach (var number in filteredArray)
  24. {
  25. Console.WriteLine(number);
  26. }
  27. }
  28. static int[] myFilter(input one, input two, int[] arrayToFilter)
  29. {
  30. var firstSymbol = ConvertOperationToSymbol(one.operation);
  31. var secondSymbol = ConvertOperationToSymbol(two.operation);
  32. string dynamicQuery = $"it {firstSymbol} {one.filter} || it {secondSymbol} {two.filter}";
  33. return arrayToFilter.AsQueryable().Where(dynamicQuery).ToArray();
  34. }
  35. static string ConvertOperationToSymbol(string? operation)
  36. {
  37. switch (operation)
  38. {
  39. case "less than":
  40. return "<";
  41. case "less than or equal to":
  42. return "<=";
  43. case "greater than":
  44. return ">";
  45. case "greater than or equal to":
  46. return ">=";
  47. case "equal to":
  48. return "==";
  49. case "not equal to":
  50. return "!=";
  51. default:
  52. throw new ArgumentException("Invalid operation phrase.");
  53. }
  54. }
  55. }

展开查看全部
u7up0aaq

u7up0aaq2#

您应该需要强大的 * System.Linq.Expressions * 来构造表达式树和过滤器。

  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using System.Linq.Expressions;
  4. public static int[] BuildFilter(int[] source, params Input[] inputs)
  5. {
  6. var param = Expression.Parameter(typeof(int), "x");
  7. List<BinaryExpression> expressions = new List<BinaryExpression>();
  8. BinaryExpression combineExpression = null;
  9. if (inputs != null && inputs.Any())
  10. {
  11. foreach (Input input in inputs)
  12. {
  13. var constant = Expression.Constant(input.filter);
  14. switch (input.operation)
  15. {
  16. case "equal to":
  17. expressions.Add(Expression.Equal(param, constant));
  18. break;
  19. case "not equal":
  20. expressions.Add(Expression.NotEqual(param, constant));
  21. break;
  22. case "less than":
  23. expressions.Add(Expression.LessThan(param, constant));
  24. break;
  25. case "less than or equal to":
  26. expressions.Add(Expression.LessThanOrEqual(param, constant));
  27. break;
  28. case "greater than":
  29. expressions.Add(Expression.GreaterThan(param, constant));
  30. break;
  31. case "greater than or equal to":
  32. expressions.Add(Expression.GreaterThanOrEqual(param, constant));
  33. break;
  34. default:
  35. throw new Exception("Operation is not supported");
  36. }
  37. }
  38. combineExpression = expressions[0];
  39. foreach (var expr in expressions.Skip(1))
  40. {
  41. combineExpression = Expression.OrElse(combineExpression, expr);
  42. }
  43. }
  44. var lambda = combineExpression != null
  45. ? Expression.Lambda<Func<int, bool>>(combineExpression, param)
  46. : Expression.Lambda<Func<int, bool>>(Expression.Constant(true), param);
  47. return source.Where(lambda.Compile())
  48. .ToArray();
  49. }

字符串
呼叫方方法:

  1. Input[] input = new Input[]
  2. {
  3. new Input { operation = "less than" , filter = 9 },
  4. new Input { operation = "equal to", filter = 10 }
  5. };
  6. int[] arraytoFilter  = new int[] { 1,2,3,4,5,6,7,8,9,10,11,12 };
  7. var result = BuildFilter(arraytoFilter, input);

展开查看全部

相关问题