#c# #linq
#c# #linq
Вопрос:
Я решил внедрить System.Linq.Dynamic
пространство имен в свой проект, где я полагаюсь на динамический вызов выражений LINQ из строки для моих базовых объектов. Это позволяет легко настраивать критерии на уровне данных.
string expression = "x.Client == 100 amp;amp; x.Insurers.Any(it == 2 || it == 3)";
var x = new MyObject() { Client = 100, Insurers = new int[] { 1, 2 }};
var p = Expression.Parameter(typeof(MyObject), "x");
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, expression);
bool result = e.Compile().DynamicInvoke(x); // True = condition met
Мой вопрос заключается в том, как мне динамически определять количество условий, содержащихся в каждом строковом выражении, чтобы я мог присвоить каждому выражению вес и выбрать то, которое имеет наибольший вес, когда происходит перекрытие. Regex
может работать, но должно быть что-то более эффективное и практичное, например, дерево выражений.
Пример.:
x.Client == 100 // Conditions = 1
x.Client == 100 amp;amp; x.Insurers.Any(it == 3) // Conditions = 2
x.Client == 100 amp;amp; x.Insurers.Any(it == 2 || it == 3) // Conditions = 3
Ответ №1:
Я не знаком с System.Linq.Dynamic
библиотекой, но предполагая, что она создает обычные, строго типизированные Expression
деревья, вы можете использовать ExpressionVisitor
.
Этот подсчитывает количество булевых логических операций, таких как amp;amp;
:
int CountConditions(Expression expr)
{
var visitor = new CountBinaryOpsVisitor();
visitor.Visit(expr);
return visitor.BinaryOperationCount 1;
}
class CountBinaryOpsVisitor : ExpressionVisitor
{
public int BinaryOperationCount { get; private set; }
protected override Expression VisitBinary(BinaryExpression node)
{
switch (node.NodeType)
{
case ExpressionType.And:
case ExpressionType.AndAlso:
case ExpressionType.Or:
case ExpressionType.OrElse:
case ExpressionType.ExclusiveOr:
// Don't count bitwise integer operations, if they are even supported?
if (node.Left.Type == typeof(bool))
BinaryOperationCount ;
break;
}
return base.VisitBinary(node);
}
}
Альтернативным подходом было бы подсчитать количество операторов сравнения ( ==
, >=
и т.д.), Но я думаю, что для этого потребуется более сложный код для обработки логических выражений, таких как x.BooleanProp
или x.Insurers.Any()
.
В настоящее время эта реализация не учитывает условные выражения ( x ? y : z
). Не уверен, как бы вы отнесли их к числу условий, особенно когда они вложены.
Комментарии:
1. Подсчет операторов сравнения должен работать так же легко, как подсчет логических операторов, просто это другой набор
ExpressionType
операций.2. @NetMage Сложность, на которую я ссылался, заключается в том, что логическое выражение like
x => x.BooleanProperty
не генерирует никакого конкретного сравнения или выражения истинности, это простоMemberAccess
илиCall
и т.д. Таким образом, вам нужно будет отличать логические значения от других обращений к элементам, таких какx.Foo.Bar.IntegerProperty
, а затем убедитесь, что вы не считаетеx.BooleanExpression == true
дважды.3. Подобные ответы @kalimag заставляют меня осознать, как много еще мне предстоит узнать о C #. Спасибо!