3

Suppose I have the following class...

public class Person {
  public string Name { get; set; }
  public string Nickname { get; set; }
}

...and I want to be able to check (separately) if the Name or Nickname properties start with an "a".

I could write two methods like this...

public bool NameStartsWithA(Person p) {
  return p.Name.ToLower().StartsWith("a");
}

public bool NicknameStartsWithA(Person p) {
  return p.Nickname.ToLower().StartsWith("a");
}

However, this violates DRY (not a big issue in this artificially simple example, but could be significant in the real world).

Searching around, it seems that the answer to this is to do the following...

public bool StartsWithA(Person p, Expression<Func<Person, string>> f) {
  return f.Compile()(p).ToLower().StartsWith("a");
}

...which can then be called as follows...

bool b = StartsWithA(person, p => p.Name);

This works fine, but I want to know what the point of the Expression is. If I remove it, and make the method look like this...

public bool StartsWithA(Person p, Func<Person, string> f) {
  return f(p).ToLower().StartsWith("a");
}

...it seems to work just as well.

Is there any point to the Expression? Looking at "Why would you use Expression> rather than Func?" it seems that the Expression doesn't give me any benefit in this case (other than a weeny improvement in execution speed, which may or may not be significant depending on the scenario), as all I'm doing is executing it, not modifying it.

Avrohom Yisroel
  • 8,555
  • 8
  • 50
  • 106
  • 1
    Doesn't `Expression` just store data about the function? If you are not doing anything with the data then there is no reason to store it. There might be an advantage if you were to modify expression before compiling it. – FCin Jan 04 '18 at 15:01
  • 1
    If you're just going to compile the expression and call it, it would *probably* be better to take a delegate. – Lasse V. Karlsen Jan 04 '18 at 15:01
  • 1
    In this case, no there isn't any reason to use `Expression`. – Lee Jan 04 '18 at 15:02
  • @LasseVågsætherKarlsen By "take a delegate" do you mean use a `Func` (as in my second version), or did you mean something else? If something else, please could you clarify what, and why it would be better than the `Func` – Avrohom Yisroel Jan 04 '18 at 15:03
  • 1
    Why must you use a Func at all? Can't you just call a static `StartsWithA(string)` and pass the property as a parameter? – Chris Pickford Jan 04 '18 at 15:04
  • @ChrisPickford Or just `person.Name.StartsWith("a")` and not even have a function – DavidG Jan 04 '18 at 15:06
  • @ChrisPickford In this simple example, yes you could. My real use case is much more complex, and I couldn't do that. I needed to pass in something runnable that specified which property to use, as I needed to call that code against more than one object of the same type. – Avrohom Yisroel Jan 04 '18 at 15:07
  • @AvrohomYisroel sounds like you're over complicating what should be a trivial task. If you're passing in a reference to an object, and a delegate to select a property from that object type, then ipso facto you could just pass the property value. – Chris Pickford Jan 04 '18 at 15:10
  • Ahhhh! Fingernails on a black-board. if (p.Name[0].ToUpper() == 'A') { /* etc */ }. Profiling your code so you'll get a sense of what is performant code is an important learning experience. – Hans Passant Jan 04 '18 at 15:12
  • @HansPassant Didn't you read my original question? I pointed out that this was a stupidly simple example to demonstrate the question. – Avrohom Yisroel Jan 04 '18 at 15:29
  • Oh, if only we could work from realistic examples. "Yes you are right" can't be that helpful either. – Hans Passant Jan 04 '18 at 15:31
  • @ChrisPickford I know what you mean, but it isn't that simple. I did try it that way originally, but it wasn't working, which is why I turned to this approach. Thanks for the comment though, I am as guilty of over complicating things as the next dev at times! – Avrohom Yisroel Jan 04 '18 at 15:32
  • @AvrohomYisroel May I suggest that you revise your question to demonstrate the peculiarities of your code and why you are tied to the delegate approach? – Chris Pickford Jan 04 '18 at 15:35
  • @ChrisPickford I don't think it would help. The amount of code/text I would need to add would be significant, but the underlying issue (ie that I'm only executing the `Expression` not modifying it) would remain the same, so I don't think it would benefit anyone. Thanks anyway. – Avrohom Yisroel Jan 04 '18 at 15:42

1 Answers1

3

it seems that the Expression doesn't give me any benefit in this case

Yes you are right.

Normally expression is used when we want to play around with the body of the function that is passed in to the lambda expression, in normal cases where we just need to execute a method in memory on some data that is already in memory Func should be good to go.

In the post you referred in the question you can see the answer higlighting that it can be useful when implementing some data fetch logic in Linq To Sql or Entity Framework as they use Expression to inspect the information passed in and then translate it to the SQL statements.

From Mehrdad's answer quoted:

Conceptually, Expression<Func<T>> is completely different from Func<T>. Func<T> denotes a delegate which is pretty much a pointer to a method and Expression<Func<T>> denotes a tree data structure for a lambda expression. This tree structure describes what a lambda expression does rather than doing the actual thing.

So it's quite clear that how much these two are different and this should give you enough idea when to use which.

Hope it Helps!

Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160