组合表达

时间:2012-02-17 09:16:13

标签: c# expression-trees

我是新手使用表达式,我在一个例子中遇到了一些问题。

我想要实现的是创建一个表达式,其中包含2个(或多个)表达式。

例如:

public static Expression<Func<Occurrence, bool>> ReporterStartsWithAndClosed()
{
    ParameterExpression occPar = Expression.Parameter(typeof(Occurrence));

    MemberExpression recorderProp = Expression.Property(occPar, "Reporter");
    MemberExpression fullnameProp = Expression.Property(recorderProp, "FullName");
    ConstantExpression letter = Expression.Constant("A", typeof(string));
    MethodInfo miStartsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
    MethodCallExpression mCall = Expression.Call(fullnameProp, miStartsWith, letter);

    MemberExpression oiProp = Expression.Property(occPar, "OccurrenceIncident");
    MemberExpression statusProp = Expression.Property(oiProp, "OccurreceIncidentStatus");
    MemberExpression nameProp = Expression.Property(statusProp, "Name");
    ConstantExpression name = Expression.Constant("Closed", typeof(string));
    BinaryExpression equalTo = Expression.Equal(name, nameProp);

    return ...?
}

我遇到的问题是如何组合这些表达式以返回此方法的正确类型。即将mCall和equalTo表达式的逻辑组合起来的语法是什么。

我最初的想法是我应该使用BlockExpressions,但我无法使用它。

非常感谢任何帮助。

由于 大卫

1 个答案:

答案 0 :(得分:1)

因此要进行逻辑AND,请使用AndAlso()方法生成表达式。然后,为了完成你的方法,你需要将这个组合方法放入lambda表达式。

只是一些提示,我会避免在你的声明中写出类型,这会使一切更难阅读。此外,您可以使用Call()的此重载按名称调用方法,因此无需获取方法的MethodInfo对象。

我会像这样(未经测试)把它放在一起:

public static Expression<Func<Occurrence, bool>> ReporterStartsWithAndClosed(
    string letter = "A")
{
    // occurrence =>
    //      occurrence.Reporter.FullName.StartsWith("A")
    //
    //      occurrence.OccurrenceIncident.OccurrenceIncidentStatus.Name == "Closed"
    var occurrence = Expression.Parameter(typeof(Occurrence), "occurrence");

    var reporter = Expression.Property(occurrence, "Reporter");
    var fullName = Expression.Property(reporter, "FullName");
    var startsWithLetter = Expression.Call(
        fullName,
        "StartsWith",
        null,
        Expression.Constant(letter, typeof(string))
    );

    var incident = Expression.Property(occurrence, "OccurrenceIncident");
    var status = Expression.Property(incident, "OccurrenceIncidentStatus");
    var name = Expression.Property(status, "Name");
    var equalsClosed = Expression.Equal(
        name,
        Expression.Constant("Closed", typeof(string))
    );

    var body = Expression.AndAlso(startsWithLetter, equalsClosed);
    return Expression.Lambda<Func<Occurrence, bool>>(body, occurrence);
}