1

I have seen a number of similar posts and it seems as though the var1 I have declared seems to need to be passed in elsewhere, but I can't seem to figure it out.

public Expression<Func<ElementNode, bool>> CreateEqualNameExpression(string match)
{
    var parm = Expression.Parameter(typeof(ElementNode), "element");

    var expr = Expression.Call(parm, typeof(ElementNode).GetProperty("Name").GetGetMethod());
    var var1 = Expression.Variable(typeof(string), "elementName");
    var assign = Expression.Assign(var1, expr);

    var parm2 = Expression.Constant(match, typeof(string));

    var exp = Expression.Equal(assign, parm2);

    return Expression.Lambda<Func<ElementNode, bool>>(exp, new[] { parm });
}

basically I'm trying to create a method that represents

(ElementNode ele) => ele.Name == match;

but I'm having a really hard time coming up with the solution. Any help would be greatly appreciated.

I'm getting the error: 'elementName' of type 'System.STring' referenced from scope'', but it is not defined.

MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
peinearydevelopment
  • 11,042
  • 5
  • 48
  • 76
  • 1
    I don't see any local variables or assignments in the expression you're trying to create, so why are you trying to use them in your code? – svick Nov 07 '13 at 08:17

3 Answers3

3

As others have said, you do not actually need the intermediate variable, but seeing as you're trying to learn about expression trees, it's good information to know.

Local variables must be declared within a BlockExpression:

public Expression<Func<ElementNode, bool>> CreateEqualNameExpression(string match)
{
    var parm = Expression.Parameter(typeof(ElementNode), "element");

    var expr = Expression.Property(parm, "Name");
    var var1 = Expression.Variable(typeof(string), "elementName");
    var assign = Expression.Assign(var1, expr);

    var parm2 = Expression.Constant(match, typeof(string));

    var exp = Expression.Equal(var1, parm2);

    return Expression.Lambda<Func<ElementNode, bool>>(
        Expression.Block(new[] { var1 }, assign, exp),
        parm);
}

Which approximately creates:

element => { var elementName = element.Name; return elementName == <constant>; }

Note that I used the Property method to build a property accessor rather than using Call. This is the preferred way of accessing properties, unless the property is non-public.

Mike Strobel
  • 25,075
  • 57
  • 69
2

Do you want the disgustingly easy version?

Expression.Lambda<Func<ElementNode, bool>> func = elem => elem.Name == match;

.Net will build the expression tree for you.


By the way, the code has a fault, it should be comparing var1 against the match (parm2), not 'assign'

var exp = Expression.Equal(var1, parm2);
Will
  • 2,512
  • 14
  • 19
  • Thanks. That will work, but as this is my first experimentation with Expressions, I would like to know how to build it up myself to further my understanding. Thanks for pointing out the fault as well. I had your suggestion before and forgot to change it back before posting. – peinearydevelopment Nov 07 '13 at 14:19
  • @peinearydevelopment If you want to learn what the compiler does, I suggest you look at what the compiler does with a decompiler such as IlSpy (turn off the option to decompile expressions). – Kris Vandermotten Nov 07 '13 at 19:28
1

As svick said, there's no need for the assignment:

public Expression<Func<ElementNode, bool>> CreateEqualNameExpression(string match)
{
    var parmExpr = Expression.Parameter(typeof(ElementNode));

    var propertyExpr = Expression.Property(parmExpr, "Name");
    var constExpr = Expression.Constant(match, typeof(string));

    var isEqualExp = Expression.Equal(propertyExpr, constExpr);

    return Expression.Lambda<Func<ElementNode, bool>>(isEqualExp , new[] { parmExpr });
}
Shlomo
  • 14,102
  • 3
  • 28
  • 43