top of page

Tips for writing Clean C# Code



Clean code is the art of writing the code that humans can understand easily. Writing code is not easy task, but when it comes to writing quality code it becomes even more difficult.


Benefits of clean code:

  • Easier to maintain : Saving your time during development. Longer code likely to cause more bugs.

  • Easier to spot bugs : It is easier to identify the cause of the code.

  • Easier to understand : There are more developers who work on one project. Write clean code that is easy to understand and not consuming time to edit.

  • Easier for Search Engine to Understand : More long and messy code will be there in website, the more search engine spider will have to sift through to find the content they are looking for, which prevent your site being indexed appropriately.

1. Naming Conventions

Naming conventions refer to the declaration of object names. You should follow this to have nice and coherent code when naming your objects. To declare a variable that returns a single entity/object, we use a simple name. To declare a variable that returns multiple entities/objects, it is necessary to add the suffix “s” or “List” so that we can easily identify that it will return a list of classes/objects:


//avoid
var Item = new Item();
var ItemList = new List<Item>();

//use
var item = new Item();
    var items = new List<Item>();
    //or  
    var itemList = new List<Item>();
    
    //To declare a private variable, we use an underline (_)
    
    //avoid 
    private int value = 10;
    
    //use
    private int _value = 10;

2. Optimizing the Syntax

We talked about how, in programming, there are several ways to do the same thing, but one thing that can always improve your code is syntax optimization. Below are some examples.

  • To declare a method that returns only one result, we can declare it as follows:

//Avoid  
public ActionResult Dashboard()
{
    return View();
}

//Use  
public ActionResult Dashboard() => View();

  • To check for null or empty conditions, use the following:

var varName = "John";
//Avoid  
if (varName != null && varName != "")
{
    //code  
}

//Use
if (!string.IsNullOrEmpty(varName))
{
    //code  
}

//or (In C# 9 or more)
if (varName is { Length: >0 })
{
    //code
}

  • To check a null value, use:

Test test = new Test();

//Avoid  
var varName = test.Name != null ? test.Name : string.Empty;

//Use  
var varName = test.Name ?? string.Empty;

  • To join strings, use:

Test test = new Test();

//Avoid  
var details = string.Format("{0}, you are welcome, Your Id is {1}", test.Name , test.Id + "_emp");

//Use  
var details = $"{test.Name}, you are welcome, Your Id is {test.Id}_emp";

//or
var details = string.Join(" ,", test.Name, "you are welcome, Your Id is", test.Id, "_emp");

  • This last block of code demonstrates how to use the new form of switch introduced in C# 8:

string firstName = "Thomas";
string favoriteTask = string.Empty;

//Good  
switch (firstName)
{
    case "Jennifer": 		
        favoriteTask = "Writing code";
        break;
    case "Thomas": 		
        favoriteTask = "Writing blog post";
        break;
    default: 		
        favoriteTask = "Watching TV";
        break;
}
//Better 
favoriteTask = firstName switch
{
    "Jennifer" => "Writing code",
    "Thomas"  => "Writing blog post", 	
    _ => "Watching TV",
};

3. Primitive Data Type Validation

With the rush of everyday life, we sometimes forget that there are methods available to validate primitive data types such as System.Int32.

When you need to do these validations, avoid using custom methods. Instead use the methods already available in the language for this.


//Avoid
public bool CheckIfIsNumber(string value)
{
    bool isNumeric = true;
    try
    {
        int i = Convert.ToInt32(value);
    }
    catch (FormatException ex)
    { 		
        isNumeric = false;}return isNumeric;
    }
    
    //Use
    public bool CheckIfIsNumberic(string value) => int.TryParse(value, out int _);

4. Using Conditional Operator “?” (Ternary) To Null Value Verification

One way to follow the concept of “Clean Code” and improve the readability and writing of your code in C# is to use the ternary operator “?”.


You can use it in cases where a statement checks for the possibility of a value being null—the null coalescence operator can be used to ensure that a non-null value is returned. The code below returns the name of the contact received or the default name if the item is null. As you can see, this operator is a great choice when working with the null condition.


//Avoid
public static string CheckContactNameError(Contact contact)
{
    var defaultName = "Default";
    
    if (contact.Name != null)
    {
        return contact.Name;
    }
    else
    {
        return defaultName;
    }
}

//Use
public static string CheckContactName(string contactName) => contactName ?? "Default";

5. Optimizing Queries with LINQ

Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query capabilities directly into the C# language.


LINQ simplifies the queries by offering a consistent model for working with data across various kinds of sources and formats. In a LINQ query, you are always working with objects. You use the same basic coding patterns to query and transform data in XML documents, SQL databases, ADO.NET Datasets, .NET collections and any other format for which a LINQ provider is available.


Below we will get a list of “Good Prices” by going through a list of “Companies” that have “Products” with various “Market Prices”.


If the Market Price is less than 100, then we add the Product to the Good Prices list and return it at the end of the expression.


//Good
public GoodPrice GetGoodPricesGood(List<Company> companies)
{
    GoodPrice goodPrices = new GoodPrice();
    
    foreach (Company company in companies)
    {
        foreach (Product product in company.Products)
        {
            if (product.MarketValue < 100)
            { 				
                goodPrices.Products.Add(product);
            }
        }
    }
    return goodPrices;
}

//Better
public GoodPrice GetGoodPricesBetter(List<Company> companies)
{
    GoodPrice goodPrices = new GoodPrice();  	
    
    IEnumerable<Product> lambdaProducts = companies.SelectMany(c => c.Products).Where(p => p.MarketValue < 100); 	
    goodPrices.Products = lambdaProducts.ToList();
    
    //Or
    //If you are not a fan of lambda expressions
    var products = from company in companies 				   
                   from product in company.Products
                   where product.MarketValue < 100
                   select product;  	
    goodPrices.Products = products.ToList();
    
    return goodPrices;
}

6. Filling Object Properties

Setting an object’s values is very common during development and there are many ways to do this. But with this tip, you can make it simpler and more intuitive, besides making the test implementation process easier.


For this, we will use a paradigm called “Fluent Code.” It is inspired by LINQ, which we’ve already covered in this article. You can research more about “Fluent Code”—it is common to use for test projects where object filling is repeated frequently.


Let’s take an example:


//Good
public class Contact
{
    public string Name { get; set; }
    public string Email { get; set; }
    public long Phone { get; set; }
}

public static Contact FillContactReady()
{
    Contact contact = new Contact(); 
     	
    contact.Name = "John Smith"; 	
    contact.Email = "johnsmith@email.com"; 	
    contact.Phone = 25454471414;return contact;
}

//Better
public class FluentContact
{
    public class Contact
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public long Phone { get; set; }
    }
    
    public Contact contact = new Contact();
    
    public FluentContact AddName(string name)
    { 		
        contact.Name = name;
        return this;
    }
    
    public FluentContact AddEmail(string email)
    { 		
        contact.Email = email;
        return this;
    }
        
    public FluentContact AddPhone(long phone)
    { 		
        contact.Phone = phone;
        return this;
    }
}
    
public static FluentContact FillFluentContactReady()
{
    return new FluentContact()
    .AddName("John Smith")
    .AddEmail("johnsmith@email.com")
    .AddPhone(25454471414);
}

7. Enum Flags Attribute

Using flags attribute to decorate the enum in C# enables it as bit fields. This enables developers to collect the enum values. One can use the following C# code.

class Program
     static void Main(string[] args)
         int snakes = 14;
         Console.WriteLine((Reptile)snakes);

[Flags]
enum Reptile
       BlackMamba = 2,
       CottonMouth = 4,
       Wiper = 8,
       Crocodile = 16,
       Aligator = 32

The output for this code will be “BlackMamba, CottonMouth, Wiper”. When the flags attribute is removed, the output will remain 14.


8. Data Type Conversion

More often than not, developers have to alter data types for different reasons. For example, converting a set value decimal variable to an int or Integer, the explicit conversion is done as follows.

int j = 0;

decimal money = 9500.34m;

j = (int)money; // An explicit conversion using cast operator.

Using the Convert class which supports full Data Type conversion between all data types is the best option.

int money = 0;
string uservalue = null;
uservalue = Console.ReadLine();
money = Convert.ToInt32(uservalue);

In the former code-snippet, an explicit conversion is done using a cast operator. In the latter code-snippet, the Convert class is used while the ToInt32() method is invoked to convert a string into an int. Explicit conversions require a cast operator. In addition, the destination and source variables should be compatible. Conversion with the assistance of a helper class such as Convert enables us to convert between non-compatible types. This does not need the use of a cast operator.


9. Establishing whether a String is Null?

A string.IsNullOrEmpty tests strings by looking for null or empty string references. The static method IsNullOrEmpty allows developers to test whether a string is empty or null. See below

if (string.IsNullOrEmpty(s))
    return "This string is null or empty.";
else
    return string.Format("This string is not null or empty, it equals to \"{0}\" ", s);


10.Tuples

Many developers build a POCO class in order to return multiple values from a method. Tuples are initiated in .NET Framework 4.0. They can be used effectively as follows

public Tuple < int, string, string > GetEmployee()
int employeeId = 1001;
string firstName = "Rudy";
string lastName = "Koertson";

//Create a tuple and return
return Tuple.Create(employeeId, firstName, lastName);

11. Object Initializers

When using the outdated method of initializing property values from outside the class, developers have to initialize the properties separately or write using a constructor. See the following example

Child child = new Child();

child.Age = 10;

child.Name = "Bryan";

child.StreetAddress = "Seattle, WA 98124";

This code can be written as:

Child child = new Child() 
{ 
    Age = 10, 
    Name = "Bryan", 
    StreetAddress = "Seattle, 
    WA 98124" 
};

12. Nullable Types

C# developers know how to work with various value types such as so one, chat, double, bool, and int. While they are useful, all of them can't be set to null. For instance, a bool variable will only hold the values either false or true. Inserting the symbol ("?") makes it possible to assign null.

Nullable<bool> status = null;
int? i = null;



The Tech Platform

0 comments

Comments


bottom of page