✨ Shield now has support for Avalonia UI

These 5 C# Guidelines (Revealed by a Senior Developer) will Change your Coding Style

Jun 17, 2022 | .NET, C#

Learning how to code can be challenging, but following the advice of more experienced developers can help you master the fundamentals of coding quickly and easily. These five C# guidelines, revealed by a senior developer, will change the way you write your code; this article will show you how to start coding like a pro today!

These guidelines are provided by Milan Jovanović, Senior Software Engineer at HTEC Group, a huge technology company that has raised a whopping $140M in its latest round of investment alone!

Define temporary variables in LINQ “Query” syntax

This first guideline, Milan comments that there is the possibility of defining temporary variables in LINQ “Query” syntax. 

It is curious because he has been talking to developers and many of them were completely unaware of this feature. And for this reason he has decided to explain it:

“Using the let keyword, you can define a temporary value in your LINQ queries. You can use it for further calculation or return this value as a result.”

from user in _dbContext.Set<User>().AsNoTracking()
where user.Id == userId
let name = $"{user.FirstName} {user.LastName}"
let hasFirstName = !string.IsNullOrEmpty(user.FirstName)
let hasLastName = !string.IsNullOrEmpty(user.LastName)
select new
    Name = name,
    ProfileComplete = hasFirstName && hasLastName

Another point he makes is that when writing EF Core (Entity) queries, the clause used (let) is also translated into proper SQL.

In addition, it advises to test it and inspect the generated SQL:

“Not everything is supported like with in-memory LINQ.”

📚Here you can read his explanation: Define temporary variables in LINQ “Query” syntax

Switch statement to compute a value

He has also decided to share a best practice when writing clean code in C#. I personally have seen quite a few cases like this and that’s why I recommend you to check it out.

Milan tells us that from C# 8 onwards you can use switch expressions to replace the switch instruction.

Bad way:

switch (DateTime.Now.DayOfWeek)
    case DayOfWeek.Monday:
    case DayOfWeek.Tuesday:
    case DayOfWeek.Wednesday:
    case DayOfWeek.Thursday:
    case DayOfWeek.Friday:
        return "Not Weekend";

    case DayOfWeek.Saturday:
    case DayOfWeek.Sunday:
        return "Weekend";
        throw new ArgumentOutOfRangeException();

Good way:

DateTime.Now.DayOfWeek switch
    not (DayOfWeek.Saturday or DayOfWeek.Sunday) => "Not Weekend",
    DayOfWeek.Saturday or DayOfWeek.Sunday => "Weekend",
    _ => throw new ArgumentOutOfRangeException()

In addition, he says that there is room for improvement:

“Also, beginning with C# 9, we can add logical pattern matching operators into the mix for even more flexibility.”

📚Here you can read his explanation: Switch statement to compute a value

Create a lazy-thread-safe-Singleton implementation

Here the questions arise as to how to create a lazy-thread-safe-Singleton implementation.

According to Milan, there are a variety of ways to do this but you should always rely on locking to prevent simultaneous access to make the implementation for thread-safe.

Milan warns that this practice would require a fairly advanced knowledge of locking mechanisms.

“However, we can utilize the Lazy class to “lazily” instantiate an instance of a class.”

public sealed class Singleton
    private static readonly Lazy<Singleton> LazyInstance =
    new Lazy<Singleton>(() => new Singleton());

    private Singleton()

    public static Singleton Instance => LazyInstance.Value;

Finally, he comments that concurrency is not important:

“Lazy is also thread-safe by default, so you don’t have to “think” about concurrency.”

📚Here you can read his explanation: Create a lazy-thread-safe-Singleton implementation

Create and use local functions

For those who do not know what a local function is, local functions allow you to declare a method inside the body of a previously defined method. This feature was added in C# 7 and Milan has decided to explain it in a clear way:

“Local functions are only visible inside the scope of their containing member. Usually, you would define and use them inside of another function.”

public IEnumerable<string> CapitalizeFirstLetter(IEnumerable<string> enumerable)
    if (!enumerable.Any())
        throw new ArgumentException("The sequence is empty.");

    return enumerable.Select(CapitalizeFirstLetterLocal);
    static string CapitalizeFirstLetterLocal(string input) =>
        input switch
            null or "" => throw new ArgumentNullException(nameof(input)),
            _ => string.Concat(input[0].ToString().ToUpper(), input.AsSpan(1))

Another thing Milan adds is that there is also the possibility for local functions to be static, as long as they do not have access to the instance members.

“It is interesting to combine local functions with iterators.
Iterators are lazy be design. But you may want to perform an argument check eagerly, which is where local functions can be helpful.”

📚Here you can read his explanation: Create and use local functions

Combine local functions with iterator blocks

Let’s continue with the local functions! This time Milan wanted to share that there is the possibility to achieve lazy evaluation with iterator blocks while having an eager argument check.

“Notice that the local function uses the “yield return” statement, which executes when enumeration happens. If the iterator block is inside of “ReadFileLineByLine” directly, you will get the exception only when enumerating the results.”

public IEnumerable<string> ReadFileLineByLine(string fileName)
    if (string.IsNullOrEmpty(fileName))
        throw new ArgumentNullException(nameof(fileName));

    return ReadFileLineByLineImpl();

    IEnumerable<string> ReadFileLineByLineImpl()
        foreach (var line in File.ReadAllLines(fileName))
            yield return line;

This good practice makes it possible to detect exceptions before they occur:

“The exception will throw as soon as “ReadFileLineByLine” is invoked.”

📚Here you can read his explanation: Combine local functions with iterator blocks

Thanks again to Milan Jovanović for sharing these guidelines and bringing value to the great and wonderful community of C# developers. If you liked them I would recommend you to follow him on Linkedin because he is always active and uploads a lot of valuable C# content!

You May Also Like