With C# 8 on our doorstep, I figure it is a good time to reflect on recent additions to the language that have come before. There are some great improvements you may have missed, some that I really enjoy using, and some I consider have reached canonical usage status that I think are all worth some reflection.
Method blocks are one of the most fundamental components of C#. They get used for all class methods, for property getters and setters, constructors, destructors, so many places.
Back in C# 3, we got Lambda expressions, which allowed us to generate anonymous function-like expressions that could be passed around as function pointers using Func
and Action
.
C# 6 has taken both of these concepts and made a mashup that is really powerful.
// Once again, some older code for comparison.
public class Widget
{
// A simple AutoProperty
public int MyAutoProperty { get; set; }
// A property with a custom get implementation
private string _myValueField;
public string MyValueProperty
{
get
{
return _myValueField + " is Awesome!";
}
}
// A standard method returning a value
public decimal CalculateTheAnswer()
{
return 42;
}
// A standard method returning a value with arguments
public decimal Process(string name, int size)
{
return name.Length + size * 4;
}
}
This is pretty standard readable good ol’ C# code. What C# 6 introduced is the ability to use lambda expressions as code bodies for methods and get-only members. So what does that look like for the example above?
// Let's do better!
public class Widget
{
// Again, still a simple AutoProperty
public int MyAutoProperty { get; set; }
// A property with a custom get implementation using an expression body!
private string _myValueField;
public string MyValueProperty => _myValueField + " is Awesome!";
// Lambda Lambda Llama!
public decimal CalculateTheAnswer() => 42;
// One more time!
public decimal Process(string name, int size) => name.Length + size * 4;
}
Look at all those lines of code I removed! Now that we are no longer being performance monitored based on lines of code, we can work smarter not harder. Not including whitespace and comment lines, this reduced from 20 lines down to 8. That’s over half the code removed using this one new language feature.
New? No, not really. It has been around since 2015. Seriously, why are you not using this yet?
Granted, this is not a one-size-fits-all technique. But anywhere your method body is a single expression, this is just magic to add to your code, for readability and for fewer keystrokes.
Speaking of readability, though, let’s look at a few lines for comparison to help you out with what they mean or do:
public string MyProp { get; }
This is a read-only auto property. The backing field cannot be set and stays whatever is set in the constructor. If nothing is set in the constructor it will be the default value.
public string MyProp { get; } = "I don't change for anyone";
This is a read-only auto property. The backing field cannot be set and stays "I don't change for anyone"
forever. the right-hand-side expression is evaluated once and stored against the object instance at construction. Once.
public string MyProp => "I don't change for anyone";
This is also a read-only auto property. It has no backing field. Whenever it is called it will evaluate the lambda expression () => "I don't change for anyone"
. Every time. This could be important. If your lambda needs to be dynamically dependent on other data, this is what you want/need. Otherwise, if your expression is costly, you might want to use the previous example to make sure it only runs once.
public string MyMethod() => "I don't change for anyone";
Gosh, it looks so similar, doesn’t it? Those extra ()
after the name makes all the difference. That difference is whether your public object interface is for a method (public string MyMethod();
) or a Property (public string MyProp { get; }
). Only you as the author can know which is more fitting. A rule of thumb to go by is that if the consumer should expect it to calculate each time, it is a method. If the consumer thinks it represents a part of the state of the object, it is a property.
</ >
There you have it. One more language feature to add to your codebase, one more part of C# understood as you read the code of the world. Go forth and Lambda Lambda Llama.