Skip to content

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

More Tips for Writing Better C# Code

Sep 4, 2018 • 9 Minute Read

Introduction

Before reading this guide, check out the first guide in this series Introduction to Writing Better C# Code and Tips for Writing Better C# Code.

A few things you should know prior to reading this guide:

  1. Improvements to C# that were made in its 6th version
  2. LINQ in .NET framework
  3. Asynchronous programming and Task object in C#
  4. 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.

Looping Over a Large Collection of Data

What good would an application be, if there is no looping and iteration over a collection of data? In these conditions, there are times when you would have to find a value, find a node, find a record, or perform any other traversing over the collection. In such cases, you really need to make sure you are writing clean code, as this is the area where performance and readability both matter a lot and they are correlated. With a bit of experience, I was able to overcome the wrong way of writing code for reading and traversing the data. That is exactly where LINQ experience should jump in and allow you to write programs that use the best of .NET framework to provide the best coding experience and the best experience to your users and customers.

Previously, you might have done a few of these:

      // A function to search for people
Person FindPerson(int id) {
   var people = DbContext.GetPeople(); // Returns List<Person>

   foreach (var person in people) {
      if(person.ID == id) {
         return person;
      }
   }

   // No person found.
   return null;
}

// Then do this
var person = FindPerson(123);
    

This can be an easy read for anyone trying to come up in your area. However, the code can be made even simpler and cleaner using LINQ queries in C#. There are two ways in which you can do this. One is a bit SQL-like and other is by using the Where function over the collection and passing the requirement that we have.

      // A function to search for people
Person FindPerson(int id) {
   var people = DbContext.GetPeople(); // Returns List<Person>

   return (from person in people
          where person.ID == id
          select person).ToList().FirstOrDefault();
}

// Then do this
var person = FindPerson(123);
    

This code has a bit of a SQL-like look and would enhance the readability and performance of your code. The function is similar, however, the Where function reads a bit better and leaves everything iteration oriented to .NET framework itself. .NET framework would provide best performance to the applications. Now, let us have a look at another way of writing this query in the same C# code:

      // A function to search for people
Person FindPerson(int id) {
   var people = DbContext.GetPeople(); // Returns List<Person>

   return people.FirstOrDefault(x => x.ID == id);
}

// Then do this
var person = FindPerson(123);
    

Notice that the first code returned null in the case when there was no match found. This code also does the same thing. The only the first code was worse was that it had to perform iterations over the collection itself. That local return person; would allow the program to return the control but what would happen if the data was at the last location? The complexity of this algorithm of data search would still be O(n).

Avoid Unsafe Context

C# also supports manual memory management, during the times when you have to pilot your plane yourself. The unsafe context in C# allows you to manipulate the memory, perform pointer arithmetic, read and write the data at memory locations which may not be provided access to, and so on. However, .NET framework does many things to overcome the memory issues, latency, and other stuff that goes around on disk. That also allows .NET framework to overcome the need to actually perform any memory management at all, .NET framework would do that for you.

There are many benefits of using unsafe context, such as when you want to write wrappers around the native C++ libraries. Emgu CV is one such example where you would write some of the code that handles how the native code is managed and to handle the errors in the memory in a way they would be simpler. In this context you can:

  1. Use pointer management and pointer arithmetic. You cannot perform anything on the addresses outside of this context, that is where .NET rules.
  2. Use memory management to manipulate the objects in the memory.
  3. Use C++ style of programming which is what C# was designed to do.

There are little to no benefits to this and if you should consider this in your applications, consider it wisely.

Everything Said About Unsafe Was Personal View

I also want to note that everything that I have said about the pros and cons of ‘Unsafe’ are my personal views. I do not frequently use unsafe context in my programs because there is no reason that I should consider using it in my applications. However, if your applications require native memory management, then you can use this context.

Use Lambda Expressions Where Possible

Lambdas come from the arena of functional programming and in C# it has been widely used in many ways, ranging from inline functions all the way down to getter only properties in C# 6. I will show both of the usages in C# that will make the program not only look cooler, but will also have a better performance factor; for that I will show you the IL of that C# code. I personally enjoy using lambdas in many areas, especially when I have to write inline functions in C#. Ever since getter-only properties could be written by using this concept, I have been using them and I personally believe it is better than the previous ways of doing the same thing.

1. Using Lambdas for Inline Functions

You should know some of the well-known delegates of C# programming. There are many fields where they are used, such as in the cases of event handling in your applications. For event handling, you can write your current functions like the following ones:

      // Without lamdbas
myBtn.Click += Btn_Click;

public void Btn_Click (object sender, EventArgs e) {
   // Code to handle the event
}

// With the help of lambdas
myBtn.Click += (sender, e) =>
               {
                  // Code to handle the event.
               }
    

Note that compiler will automatically map the objects to their types. This is convenient in many ways as it allows you to write the inline functions in C# that remain with the objects only, unless you want to use them anywhere else too. There is however one disadvantage to this method of handling the events: you cannot remove the event handler once it has been attached. In C# you can -+ but since we don't have any reference to remove the events, we are left only being able to use the separate functions. But, if you don't have to remove the handlers, you should always consider using this way of event handling in your programs.

2. Using Lambdas for Getter-only Properties

In C#, there is a concept of using properties instead of fields. You control how a value is set and how a value is captured from the field. Consider this as an alternative (or similar to) to the getter and setters of Java programming language. Only difference is that you don't have to write them separately somewhere, they are written right in front of the field itself. C# program compilers would then make their own backing fields that are used to store the values.

Basically, you would have to write the getter-only properties like this:

      public string Name { get; }
    

Note that these properties are constant, and you cannot change them once they are set. They were set in the constructors, or (as of C# 6) they are set right in front of it. Like this:

      public string Name { get; } = "Afzaal Ahmad Zeeshan";
    

However, since we already know that this is a constant field and you cannot modify this, then why not create a simple constant property? This is where things get a bit tricky; even a property has to be backed up by a field. In which case, this would do the trick for us:

      public string Name => "Afzaal Ahmad Zeeshan";
    

This is equivalent to writing the following:

      public string Name { get { return "Afzaal Ahmad Zeeshan"; } }
    

But the performance is much better since the getter-only field is converted to a constant field and that field is used in the program anytime this property has to be called.

Final Words

The purpose of this guide series was to allow you to understand and see a few of the ways in which your programs can be easier to read and perform better. The C# compiler itself does the most to increase the quality and efficiency of your code, whereas that is often left to the programmer, and will to make the program work better. There are many other ways of improving the readability, many of these are left to the company's way of writing the programs because most teams require programmers to follow their own programming methods and ways.