Expressions are short methods by convention. It's all about the delegation of a "thing" to do and what it takes to declare the contract: What you have and what you want in return.
It's pretty good to see in Lambdas: While you'll see this most of the time ...
var tims = users.Where(u => u.Name.StartsWith("Tim"));
... it is perfectly valid to write ...
var tims = users.Where((User u) => u.Name.StartsWith("Tim"));
... and even:
var tims = users.Where((User u) => { return u.Name.StartsWith("Tim"); });
The latter is a full featured delegate syntax with arguments (User u
) the curly braces for the method scope and the single-line body. In fact, this is quite the same method as this (except the lack of a method name):
private bool IsTim(User u)
{
return u.Name.StartsWith("Tim");
}
Which by the way would allow your lambda to look like this because IsTim()
has exactly the same signature as the predicate for the Where-clause (= the lambda determining whether a user is a match or not).
var tims = users.Where(IsTim);
Skipping the last example, all of the other three lambda predicates do exactly the same thing but look pretty different:
1 u => u.Name.StartsWith("Tim")
2 (User u) => u.Name.StartsWith("Tim")
3 (User u) => { return u.Name.StartsWith("Tim"); }
Coming from case 3
to case 1
over the last years, the .NET team tried to minimize the keystrokes necessary to achieve the same thing. Delegates 3
have been there forever but with the introduction of Lambdas and Linq, Microsoft needed to simplify the delegating signature which led us to 2
and 1
.
While case 2
is basically exact the same thing as case 3
, case 1
is only valid in the correct context. It does not define the type of u
but infers it in the context it is called. If you call this lambda on a list of users, u
will be a user object. If you call it on a list of strings, it's representing a string (and won't compile in this case).
It took a while that Microsoft took over this logic to method and even property bodies but the logic is still the same: Why won't you reduce the necessary keystrokes if you can infer the arguments, return types and methods scopes by it's context?
That's why these two methods are exactly the same:
private bool IsTim(User u)
{
return u.Name.StartsWith("Tim");
}
private bool IsTim(User u) => u.Name.StartsWith("Tim");
u.Name.StartsWith("Tim")
will always return a boolean value and the runtime already knows the arrow =>
to split the method arguments from the method body. It really is "pointing" to the expression producing the return value.
"Pointing to a return value" explains why there should not be a return
keyword in public int GetAge() => this.Age;
.