Создание выражений для другого объекта - PullRequest
1 голос
/ 07 ноября 2019

У меня есть список выражений для данного объекта. Мне нужно создать соответствующие выражения для отдельного объекта на основе выражений, представленных в списке. В настоящее время я пытаюсь вручную извлечь свойства из выражения и перестроить новое выражение для другого объекта.

foreach(var clause in list)
{
    //this needs to change since not all expressions are binary
    var exp = clause as BinaryExpression;

    var member = exp.Left as MemberExpression;
    var otherObjectMember = Expression.Property(otherObject, member.Member.Name);

    //member does not exist in otherObject
    if (otherObjectMember == null)
        continue;

    //this needs to change to handle other expression types, not only equal
    var otherObjectMemberCheck = Expression.Equal(otherObjectMember, exp.Right);

    //additional processing...
}

Приведенный выше код будет хорошо работать с этим примером списка выражений:

entity.Enabled == true
entity.Priority == 1

Проблема в том, что каждый сценарий типа выражения должен обрабатываться вручную (равно, не равно, содержит и т. Д.).

Следующие выражения не будут работать:

entity.Name.Contains("CPU")
values.Contains(entity.Name)
entity.Priority < 5
and any other non-binary expressions

Я надеюсь, что есть лучший способ справиться с переназначением выражений. Может кто-нибудь, пожалуйста, укажите мне в правильном направлении? Заранее спасибо!

Ответы [ 3 ]

1 голос
/ 08 ноября 2019

Вы можете легко сделать это, используя простой ExpressionVisitor.

using System;
using System.Linq.Expressions;

public class Visitor : ExpressionVisitor
{
    public ParameterExpression Target { get; set; } 
    public ParameterExpression Replacement { get; set; } 
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node == Target ? Replacement : base.VisitParameter(node);
    } 
}

public class Program
{
    public static void Main()
    {
        var obj = Expression.Variable(typeof(string));
        var item = Expression.Property(obj, "Length");

        var otherObj = Expression.Variable(typeof(string));
        var replacedItem = new Visitor()
        {
            Target = obj, 
            Replacement = otherObj, 
        }.Visit(item);
    }
}

Посетитель посетит каждый узел в выражении, рекурсивно. Когда находит ParameterExpression, он проверяет, является ли это переменная, которую мы хотим заменить: если это так, он возвращает замену. Конечным результатом является выражение, которое совпадает с вводом, но каждое вхождение целевой переменной заменяется заменой.

0 голосов
/ 08 ноября 2019

Это нетривиальная вещь, которую нужно сделать, так как она настроена. В настоящее время вам, в основном, придется посещать каждый член и значение каждого выражения, а затем надеяться каким-то образом обнаружить или иным образом спроецировать это выражение на вашу цель.

Это ошибочный дизайн.

Чтособирается сделать вашу жизнь проще, просто представив интерфейс, который разделяет все эти вещи.

public interface ISearchable
{
    string Name { get; set; }
    bool Enabled { get; set; }
    int Priority { get; set; }
}

, а затем используйте его для поиска по объектам

public class Machine : ISearchable {}
public class Part : ISearchable {}

, а затем вваши выражения конструкций

IList<Expression<Func<ISearchable,bool>>> list = new List <Expression<Func<ISearchable,bool>>>();

// apply entire list to ISearchable entities
0 голосов
/ 08 ноября 2019

Рассматривали ли вы создание объекта адаптера, который будет использоваться для построения выражений. Затем у вас будет лямбда для этого единственного объекта Adapter. Адаптер должен иметь свойство Target и сопоставлять его собственные свойства с базовыми свойствами Target. Затем вы можете получить выражения для различных объектов, просто изменив свойство Target адаптера.

...