David Muir
David Muir

Reputation: 139

Combined Expressions

I am new to using expressions and I am having some problems in an example I am working through.

What I am trying to achieve is to create an Expression which has 2 (or many) Expressions within.

For example:

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 ...?
}

The question I have, is how to I combine these expressions to return the correct type for this method. I.e. what is the syntax for combining the logic for mCall and equalTo Expressions.

My initial thought were that I should be using BlockExpressions but I couldn't get this to work.

Any help would be greatly appreciated.

Thanks David

Upvotes: 1

Views: 182

Answers (1)

Jeff Mercado
Jeff Mercado

Reputation: 134841

So to do a logical AND, use the AndAlso() method to generate the expression. Then to finish off your method, you'll want to put this combined method into an lambda expression.

Just some hints, I'd avoid writing out the types in your declarations, it makes everything harder to read. Also, you could call a method by name by using this overload of Call() so no need to get the MethodInfo object for the method.

I'd put it together like this (untested):

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);
}

Upvotes: 1

Related Questions