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:
Task
object in C#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.
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:
1string name = null;
2
3Console.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:
1string name = null;
2
3// Try to enter the value, from somewhere
4if(name != null) {
5 Console.WriteLine(name);
6}
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?
1var 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:
1var 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.
1var company = DbHelper.PeopleTable?.Find(x => x.id == id)?.FirstOrDefault()?.EmploymentHistory?.CompanyName;
2
3if(company != null) {
4 // Final process
5}
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.
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:
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.
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:
1string str = ""; // Setting it to null would cause additional problems.
2
3// Way 1
4str = "Name: " + name + ", Age: " + age;
5
6// Way 2
7str = string.Format("Name: {0}, Age: {1}", name, age);
8
9// Way 3
10var builder = new StringBuilder();
11builder.Append("Name: ");
12builder.Append(name);
13builder.Append(", Age: ");
14builder.Append(age);
15str = 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:
1static void Main(string[] args)
2{
3 // Just arbitrary variables
4 string name = "";
5 int age = 0;
6
7 // Our interest
8 string str = $"Name: {name}, Age: {age}";
9}
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.
1IL_0000: nop
2IL_0001: ldstr ""
3IL_0006: stloc.0 // name
4IL_0007: ldc.i4.0
5IL_0008: stloc.1 // age
6IL_0009: ldstr "Name: {0}, Age: {1}"
7IL_000E: ldloc.0 // name
8IL_000F: ldloc.1 // age
9IL_0010: box System.Int32
10IL_0015: call System.String.Format
11IL_001A: stloc.2 // str
12IL_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
.
Continue on to the next guide in this series for More Tips for Writing Better C# Code.