Tips for Writing Better C# Code
You can improve program performance in a matter of seconds by writing good C# code. The following tips do not guarantee that your code will perform better, but they can definitely help. Check out this guide and start writing better C# code today!
Dec 15, 2018 • 8 Minute Read
Introduction
Before reading this guide, check out the first guide in this series: Introduction to Writing Better C# Code.
A few things you should know prior to reading this guide:
- Improvements to C# that were made in its 6th version
- LINQ in .NET framework
- Asynchronous programming and Task object in C#
- Unsafe programming in C#, which allows you to go into memory management
Not Focusing on Performance
It should be noted that I will not talking about changing the program performance, upgrading the efficiency, or decreasing the time taken by the programs to run. You can improve program performance in a matter of seconds by writing good C# code, but the following tips do not guarantee that your code will perform better.
Null Checkup
Do you ever get annoyed by the NullReferenceException, when an object that missed initialization comes back for revenge? There are many benefits to having the null checkups in your programs, not just for better readability but also to ensure that the program does not terminate due to memory issues -such as when a variable does not exist in the memory. These can stack up against the security of your programs and the good UI and UX guidelines that your teams have. Most of the times, a null exception gets raised due to this:
string name = null;
Console.WriteLine(name);
In most cases, the compiler itself won't continue until you fix this, but if you somehow manage to trick the compiler into thinking that the variable has a value but on the runtime there is none, a null reference exception will come up. To overcome this, you can do the following:
string name = null;
// Try to enter the value, from somewhere
if(name != null) {
Console.WriteLine(name);
}
This safe checkup will ensure that the value is available when this variable is called. Otherwise, it will move in other direction and away from the buggy path. In C# 6 however, there is another way of overcoming this error. Consider a scenario where your database was set up, your table of data was set up, your person was found, but their employment details were not found. Can you get the company where they worked?
var company = DbHelper.PeopleTable.Find(x => x.id == id).FirstOrDefault().EmploymentHistory.CompanyName; // Error
If you did this there will be an error because we were only able to move up a few steps in the list of these values. Then we ended up hitting a null value and everything was lost. C# 6 came up with a new way of overcoming these cases, by using a safe navigation operator after the values and fields which can be null; ?.. Like this:
var company = DbHelper?.PeopleTable?.Find(x => x.id == id)?.FirstOrDefault()?.EmploymentHistory?.CompanyName; // Works
This code will only check for next value if the previous was not null. If the previous value was null, it will return null and save the null as the value for the company, instead of throwing the error. This can come handy where you leave the checkups to the framework itself, but, nonetheless, you still have to check at the end to see if the rest of the values are null or not.
var company = DbHelper.PeopleTable?.Find(x => x.id == id)?.FirstOrDefault()?.EmploymentHistory?.CompanyName;
if(company != null) {
// Final process
}
But you get the point, instead of writing the code and checking everything to be null, you can do a simple checkup and perform the actions and logics that you want in your programs. Otherwise, there would be a need for a try...catch wrapper or multiple if...else blocks to control how your program navigates in the system.
Asynchronous Pattern of Programming
If you are programming using C# 5, then you are already using the async/await keywords to bring responsiveness to your applications. If that is not the case, then I would recommend using an asynchronous programming pattern in your application's source code. This can not only increase the responsiveness to your programs but will also increase the readability to your application. A few of the benefits for having asynchronous pattern in your source code are:
- Code paths start to make much more sense. Programmers can understand where the program should be if there is a process that starts running in the background.
- Application hang problems will go away. Most of the application freeze related problems come directly from the code. When the UI thread cannot update the UI, users consider the application to be hanging and not responding, whereas that is not the case. An asynchronous approach can really help a lot in this.
- Windows Runtime based applications are entirely based on this approach. You will be (and must be!) using this approach in one of your Windows Runtime applications to overcome problems like hanging applications or bad programming practices.
Ever since threading, parallelization of the code execution has come into existence. Asynchrony has become a vital part of the programs and applications, so you should also consider using it.
C# String Building
Strings are a vital part of applications nowadays and building the strings can take a lot of time, along with also causing a performance lag in the applications. There are many ways in which you can build the strings in C# programs. Here are a few of those ways:
string str = ""; // Setting it to null would cause additional problems.
// Way 1
str = "Name: " + name + ", Age: " + age;
// Way 2
str = string.Format("Name: {0}, Age: {1}", name, age);
// Way 3
var builder = new StringBuilder();
builder.Append("Name: ");
builder.Append(name);
builder.Append(", Age: ");
builder.Append(age);
str = builder.ToString();
Note that strings in C# are immutable. This means that if you try to update their values, they are recreated and previous handles are removed from the memory. That is why the Way 1 may look like that is the best way to go but, upon further reflection, it is not. The best way to go to is Way 3, which allows you to build up the strings without having to recreate the objects in the memory. However, C# 6 has introduced an entirely new way of building the strings in C# that are much better than the ones that you could imagine previously. The new String interpolation operator $ provides you with the facility of performing the string building in best possible way. The string interpolation goes like this:
static void Main(string[] args)
{
// Just arbitrary variables
string name = "";
int age = 0;
// Our interest
string str = $"Name: {name}, Age: {age}";
}
Just a single line of code and the compiler will automatically convert this to the string.Format() version. For a proof, will detail the bytecode that this C# program has generated and that will show you how this would automatically change the syntax to read the formatting of the string.
IL_0000: nop
IL_0001: ldstr ""
IL_0006: stloc.0 // name
IL_0007: ldc.i4.0
IL_0008: stloc.1 // age
IL_0009: ldstr "Name: {0}, Age: {1}"
IL_000E: ldloc.0 // name
IL_000F: ldloc.1 // age
IL_0010: box System.Int32
IL_0015: call System.String.Format
IL_001A: stloc.2 // str
IL_001B: ret
As can be seen, this shows how the syntax is changed back to the one we have already seen. See the IL_0009 for more. This brings a cleaner look to your programs when someone else is reading the programs, along with increasing performance if the strings to be built are smaller. In case of larger strings, use StringBuilder.
Next Steps
Continue on to the next guide in this series for More Tips for Writing Better C# Code.