Code Style
Last modified on Thu 31 Oct 2024

It is important to keep the code readable and consistent so anybody reading it can understand it without too much effort. We use general C# Microsoft coding conventions with some additions to write our code.

These are some of the rules we would like to emphasize:

To keep things a bit easier we use StyleCop, a tool for enforcing C# style and consistency rules. The ruleset can be configured and used across all projects in the solution. It is easily installed as a NuGet package and as soon as you build the project, the StyleCop will start checking.

We also use Roslynator, a lightweight collection of analyzers, refactorings and fixes for C#. Roslynator will be even more useful when the StyleCop can't be added to legacy projects.

You can check out the rulesets we use in our public GitHub repo. We suggest that instead of copying the files to your repository you use the git submodule feature with a symlink to the required directory. That way your repository will stay up to date with a simple pull command.

There is also extensive documentation for C# available here.

These are some of the code formatting examples we follow to keep our code clean and consistent:

Ternary expressions

// single expression - single line
var result = booleanExpression ? resultA : resultB;

// single expression - multi line
var result = booleanExpression
      ? resultA
      : resultB;

// multiple expressions
var result = booleanExpressionA ? resultA
    : booleanExpressionB ? resultB
    : booleanExpressionC ? resultC
    : resultD;

Lambda expressions

// single line
var result = data.Where(x => booleanExpression).ToList();

// multi line
var result = data
    .Where(x => booleanExpression)
    .OrderByDescending(x => x.DateTime)
    .FirstOrDefault();

// nested expressions
var result = data
    .Where(x => booleanExpressionA)
    .Select(x => x.ListA
        .Where(y => booleanExpressionB)
        .OrderByDescending(y => y.DateTime)
         .FirstOrDefault())
    .ToList();

Using "Async" suffix in asynchronous method names

In asynchronous programming, one common dilemma is should the "Async" suffix in asynchronous method names be used or not.

On one side, Microsoft recommends using the suffix (as recommended in this article). On the other hand, the programmers generally tend to write expressive, but as short as possible method names. From that perspective, adding the "Async" suffix may be considered an unnecessary name extension.

We think both views are OK, and thus do not encourage nor discourage any of them. Here, it is important to make naming consistent, at least on the project level. It simplifies the maintenance, and new team members won't be confused when they start working on the project.

However, there is one case in which the "Async" suffix is mandatory. If a method has both a synchronous and an asynchronous version, the asynchronous method needs to be written with the suffix to avoid naming conflict, regardless of the project standard. Following is an example of such a case:

    // Synchronous report generation method
    public string GenerateUserReport(int userId)
    {
        // Fetch user data and create report
        var userData = FetchUserData(userId);
        return $"Report for {userData.Name} generated on {DateTime.Now}";
    }

    // Asynchronous report generation method
    public async Task<string> GenerateUserReportAsync(int userId)
    {
        // Simulate an async I/O operation
        var userData = await FetchUserDataAsync(userId);
        return $"Report for {userData.Name} generated on {DateTime.Now}";
    }

    private User FetchUserData(int userId)
    {
        // Example synchronous call; this might be a database or a cache call
        return new User { Id = userId, Name = "John Doe" };
    }

    private async Task<User> FetchUserDataAsync(int userId)
    {
        // Example asynchronous call to simulate delay; could involve an external API or slow data retrieval
        await Task.Delay(100);
        return new User { Id = userId, Name = "John Doe" };
    }