Writing More Succinct C#

10 May 2020 - C# , .NET

When looking at a lot of C# code nowadays, I find myself thinking "wow, that code could be made SO MUCH SMALLER!". C# is a very flexible language, allowing you to write clean and functional code, but also very bloated code.

There are a lot of things in the C# language that can help writing more succinct code - some older (like LINQ), and some which have been added in newer versions of C#. In this blog post, I'll talk through some of them. But let's start with a side-by-side example to add a bit of context to what I mean by smaller code...

sidebyside

Both of the above two methods do the same thing. This is obviously a fabricated example to make a point, but I do see code like this all the time in real codebases. Look at the right-hand version, and imagine getting this kind of compression, not just in one method, but across your entire codebase. It's also much more readable. If you don't find the right-hand version more readable, then I suspect you're new to LINQ, and I'd highly recommend learning it if you're a .NET developer. It's not new, it has been around since .NET 3.5 (release in 2007), and it is genuinely one of the main reasons I love .NET so much!

This example covers some of the topics I'll discuss in this blog post - eg. LINQ, ternary-if, and expression body members. But I'll also highlight some other nice ways you can make code more compact - especially if you're using C#8!

Now that we've looked at an example that adds a bit of context to what this blog post is striving for, let's dig in...

Embrace LINQ!

LINQ is AMAZING! It really is one of the main reasons I love .NET so much! It's been around since .NET 3.5, and the amount of code and complexity that it removes is incredible. The screenshot at the top of this blog post is probably one of the simplest examples of LINQ there is - and yet, look how much code it saved!

It's easy to add conditional predicates; sort order; and much more in minimal lines of codes.

myList
    .Where(x => x.SomeProperty > 10)
    .OrderBy(x => x.SomeOtherProperty)
    .ToList();

You can even easily do GroupBy and manage aggregate queries.

I'm not going to delve into LINQ here, as that's out of the scope of this blog post - however, if you're using .NET, and not comfortable with LINQ, then definitely spend a bit of time getting good at it. It'll make a massive difference to your code.

One caveat is that LINQ might not be a good fit in performance-critical code, as it can cause more allocations. So be mindful of where you use it. If you're writing performance-critical code that gets run a lot (eg. in a loop), it's worth using something like Benchmark.NET to measure the performance of that code and know where you allocations are regardless of whether you're using LINQ or not.

Expression body members (C#7)

I'm a big fan of expression body members, which allows you to do this...

int GetSomething() => 123;

instead of this...

int GetSomething()
{
    return 123;
}

Note that we've not only removed the braces, but also the return keyword. This is because this is an expression, rather than a statement. A statement is a command - ie. "return me a value", where an expression is just something that evaluates to a value. It might be a single value as it is in the above example, or it could be an algorithm, or it could be the results of a LINQ expression...

IEnumerable<OrderItem> GetOrderItems(int orderId) =>
    _orderRepository.GetOrderItems()
        .Where(x => x.OrderId == orderId)
        .ToList();

Notice the lack of braces and return keyword? Notice how compact and succinct it is, but still very readable.

I find myself trying to turn as many methods as possible into expression-body members. And thanks to the other things I mention in this post, it's surprising by how many methods end up being condensed down to a single expression that can be turned into an expression-body member.

Ternary if (?:)

Ternary if, also known as an inline-if, allows you to say "if something ? then do this : else do this".

For example, this..

string foo;

if (bar != null)
{
    foo = bar
}
else
{
    foo = "default"
}

...can be made much smaller with the ternary if...

var foo = bar != null ? bar : "default";

(and this can be made even small, see next section)

Null coalescing operator (??)

The above shortened example, can be made even smaller still with the null coalescing operator...

var foo = bar ?? "default";

This says if bar is not null, then use it, otherwise continue evaluating to the right of the ?? operator.

Null-coalescing assignment operator (??=) (C#8)

If you're using C#8, then there's also the ??= operator, which will only evaluate and assign the right-hand value, if the value on the left is null.

So this...

if (_myValue == null)
{
    _myValue = InitialiseMyValue();
}

...can be shortened to this...

_myValue ??= InitialiseMyValue();

If _myValue isn't null, then it'll be left alone, and InitialiseMyValue() won't even be called. This is really useful for initialisation.

Null conditional operator (?.) (C#6)

This is a nice bit of shorthand added into C#6, meaning that you can change this...

if (a != null && a.b != null && a.b.c != null)
{
    a.b.c.DoSomething();
}

...into this...

a?.b?.c?.DoSomething();

It basically says if the code to the left of the ?. is null, then stop evaluating anything to the right. So in the example above, if either a, b, or c is null, then it won't do anything, and won't call DoSomething(). If you were assigning the above statement to a variable, and either a, b, or c was null - then the null will be assigned to that variable.

C#8 switch expression

Another C#8 one here. I've pinched the below example from the documentation...

var orientation = direction switch
{
    Directions.Up    => Orientation.North,
    Directions.Right => Orientation.East,
    Directions.Down  => Orientation.South,
    Directions.Left  => Orientation.West,
};

This is a lot cleaner than the typical switch statement we're used to. And when you start adding the power of pattern matching into the mix, it gets even better!

Removing Braces from single-line blocks???

First of all, this one is obviously highly controversial! I'm not saying you should be omitting braces, and there are a lot of people who would find it a cardinal sin. But more and more recently, especially as I look into other languages that don't require braces - I'm finding them more and more redundant. I mean, we all indent our code don't we? If not, why not? So why do we need braces at all? Well, for single-line statements - you don't.

Omitting the braces in single-line if statements, foreach, where, using, etc. can make code much more compact. Take this example...

removingbraces

When you get used to this, it's amazing how stretched out the code on the left looks. It's really started to make me dislike the concept of braces at all in C#.

This is now where a lot of C# devs will now be screaming at their monitors, saying things like "But what about the Apple bug?!", or "But what if a Python dev who's used to not having braces, comes in and does this..."

if (something)
    doSomething();
    doSomethingElse(); // New method call added by Python dev

If you do this, your IDE/Editor is going to SCREAM at you. Unless of course, you're coding in notepad. Also, most editor's default setup is to autoformat on ; or } - so this'll be very quickly auto-indented. Obviously, you'll get the rare exception where someone has disabled all this functionality, or someone's using an editor that doesn't lint - but in the most case nowadays, you'd have to program blindfolded to get caught by this.

Re. the Apple bug, I struggle with the fact that one person wrote a bug a long time ago - and from now on, everyone has to pad out their code like shown in the screenshot above. If we had to change the way we write code every time someone writes a bug - we wouldn't be allowed to touch the keyboard.

Many years ago, I was a C/C++ developer, where it was good practice to always wrap single-line blocks in braces. There was good reason for this though. C/C++ has a concept called macros. When macros are used in code, it might look like a single-line if statement, however, when expanded out by the preprocessor, it might actually be a multiline if statement. So it can be dangerous if you don't wrap all your blocks in braces. This isn't the case in C# though.

Whilst I prefer omitting braces and find them redundant (after all, we indent our code anyway, so why do we need braces?!) - I have recently found a genuine reason why this perhaps isn't a good idea. In fact, I found it whilst writing this blog post...

stackoverflowanswer

(source)

The two comments at the bottom of that screenshot pretty much echoed my thoughts. Most other arguments against this felt like the issue was sloppy indentation, not an issue with omitting the braces. However, the above example isn't lazy programming, because it looks like it's indented correctly.

Even so, as I mentioned above - your IDE/editor is most likely going to bark at you and probably even fix the indentation for you automatically.

So yes, this makes a big difference in code size, but you have to be careful not to introduce the above-mentioned bug. So this section isn't advice on either way - it's just my thoughts on the pros and cons. As you can see from the screenshot at the start of this section, it does make quite a difference - just be careful if you decide to do this. Using some of the other techniques in this blog post can help eliminated if-else blocks altogether anyway.

Also, remember that switch case blocks do not require braces even for multi-line blocks.

Remove unnecessary local variables

Another one I see a lot is code like this..

removeunnecessarylocalvariables

There are a lot of unnecessary local variables here. We can already see what each method-call is doing from the method names, and the next method-calls are then just members of the previous method. These can be nicely chained together instead of introducing local variables...

removeunnecessarylocalvariables

It's much cleaner - especially when you get used to using fluent syntax. And as a bonus, we were then able to turn it into an expression-body-method, removing the braces and the return keyword!

Although do bear in mind that neither of these examples have error checking, and rely on exceptions being caught by calling methods. It might be that you need to store a local variable to do error checking, or to write log entries. So I'm certainly not saying to always avoid local variables - just do it intentionally, rather than blindly assigning every single method call to a local variable. The above is just an example to make a point.

Use var

Spot the duplication...

Dictionary<int, string> myVariable = new Dictionary<int, string>();

Isn't this much better?...

var myVariable = new Dictionary<int, string>();

Remember that var is still statically typed. There's no difference in what the two lines above get compiled down to.

The only argument against using var I've heard is that it's less clear. However, I've used it everywhere for years, and have never once wished I'd been more clear and used an explicit type. It's pretty much always clear from the context, and if not, just hover your mouse over it to find out what type it is.

Moving towards Functional Programming

It's clear that as the C# language evolves, we're moving more and more into a functional style of programming. LINQ was added in .NET 3.5 - and the later versions of C# are adding more and more ways to help us write code in a more functional manner, as you can see from the examples above. As we start to think in this style of programming, it becomes easier to adopt other parts of functional programming. For example, pure functions. A pure function is a function that for each input (ie. function arguments), it'll always have the same return value. A pure function itself with have no side-effects, and not change state outside of the function (eg. no database or API calls, no changing external properties, etc). With smaller, more compact expression-body methods, this becomes easier. And also easier to write tests against.

Debugging

One downside to more compact and functional code, is that it can sometimes be harder to debug. There's less code to put breakpoints against, and you can't add watches to variables that you don't have because you've avoided local variables. However, I'd much rather have a nice compact readable codebase throughout the entire codebase, and very occasionally have to add a temporarily variable assignment whilst I debug something. This is much more favourable than the entire codebase being massively bloated. Besides, modern debuggers do help, allowing you to debug into LINQ expressions and lambdas anyway.

You'll probably also find that you have less reason to debug, as a more functional codebase is likely to have fewer bugs and is easier to reason about. More pure functions also means that it's easier to run your code via a test instead, or just copy that method into a REPL where you can run it standalone.

Summary

I've given a lot of different examples in this blog post of how to make your code much more succinct and compact, whilst still being very readable (in some cases, gaining far more readability!). It's when these techniques get combined, not just in one method, but across your entire codebase, that you really start to see big differences. Everywhere I look at the moment, I'm seeing C# code that could be made so much smaller than it is. Hopefully after reading this blog post, you join me in quest to vanquish bloated C# from your codebases!

There's an interesting slideshow by Scott Wlaschion about a made-up language called C# Light, where he discusses some of the bloat in the C# language. As he warns in the initial slides, it's only for those of you who are open-minded! I certainly ended the slides thinking that we were just left with F# - which isn't a bad thing! Learning F# is what made me start to notice how bloated C# was in the first place!

Search


Recent Posts


Featured Posts


.NET Oxford Links