выражение> или выражение> к выражению> Конвертер - PullRequest
4 голосов
/ 30 мая 2011

Есть ли простой способ конвертировать

Expression<Func<TBase,bool>> 

до

Expression<Func<T,bool>>

где T наследуется от TBase?

Ответы [ 3 ]

3 голосов
/ 22 августа 2012

Пока T выводится из TBase, вы можете напрямую создавать выражение нужного вам типа с телом и параметрами исходного выражения.

Expression<Func<object, bool>> x = o => o != null;
Expression<Func<string, bool>> y = Expression.Lambda<Func<string, bool>>(x.Body, x.Parameters);
2 голосов
/ 30 мая 2011

Возможно, вам придется конвертировать вручную. Причина этого в том, что вы эффективно конвертируете в подмножество того, чем оно может быть. Все T TBase, но не все TBase T.

Хорошая новость заключается в том, что вы, вероятно, можете сделать это, используя Expression.Invoke , и применить соответствующее приведение / преобразование к TBase вручную (конечно, улавливая любые проблемы безопасности типов).

Редактировать: Я прошу прощения за неправильное понимание направления, в котором вы хотели идти. Я думаю, что просто преобразование выражения по-прежнему ваш лучший путь в любом случае. Это дает вам возможность обрабатывать преобразование так, как вы хотите. Ответ Марка Гравелла здесь - самый компактный и понятный способ, которым я когда-либо видел.

0 голосов
/ 22 августа 2012

Для этого я написал ExpressionVisitor с перегрузкой VisitLambda и VisitParameter

Вот оно:

public class ConverterExpressionVisitor<TDest> : ExpressionVisitor
{
    protected override Expression VisitLambda<T>(Expression<T> node)
    {
        var readOnlyCollection = node.Parameters.Select(a => Expression.Parameter(typeof(TDest), a.Name));
        return Expression.Lambda(node.Body, node.Name, readOnlyCollection);
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return Expression.Parameter(typeof(TDest), node.Name);
    }
}

public class A { public string S { get; set; } }
public class B : A { }

static void Main(string[] args)
{
    Expression<Func<A, bool>> ExpForA = a => a.S.StartsWith("Foo");
    Console.WriteLine(ExpForA); // a => a.S.StartsWith("Foo");

    var converter = new ConverterExpressionVisitor<B>();
    Expression<Func<B, bool>> ExpForB = (Expression<Func<B, bool>>)converter.Visit(ExpForA);
    Console.WriteLine(ExpForB); // a => a.S.StartsWith("Foo"); - same as for A but for B
    Console.ReadLine();
}
...