DEV Community 👩‍💻👨‍💻

Cover image for 5 C# Tips from a Senior Developer to Help You Program Better
ByteHide
ByteHide

Posted on • Updated on • Originally published at blog.dotnetsafer.com

5 C# Tips from a Senior Developer to Help You Program Better

Senior developers tend to pick up many tricks and workarounds over the years, but most of them never make it into articles, blog posts or books. If you’re just starting out as a C# developer, or if you’re looking to improve your skills, here are some tips from some of a Senior Developer on how to program better using C#.

They will help you improve your coding abilities with this powerful language so, I hope you find these tips useful as you continue on your programming journey!

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!

I very recommend you to follow him on Linkedin because he is always sharing valuable content about C#.


Expression-Bodied Constructors

For this first tip, Milan reports that there is the possibility of creating expression-bodied constructors using the different characteristics introduced by the tuples:

“You can create a tuple from the constructor arguments and then deconstruct that tuple into the respective properties.”

Expression-bodied members have the ability to easily provide the implementation of a member. This is useful as long as the property or method consists of only a single expression.

Here Milan shows first the before:

public class Person
{
    public string Name { get; }
    public int Age { get; }

    public Person (string name, int age)
    {
        Name = name;
        Age = age;
    }
}
Enter fullscreen mode Exit fullscreen mode

Then, Milan shows the after of what it would look like:

public class Person
{
    public string Name { get; }
    public int Age { get; }

    public Person(string name, int age) => (Name, Age) = (name, age);
}
Enter fullscreen mode Exit fullscreen mode

Some people may think at first glance that this affects performance, but Milan disproves this:

“It won’t affect performance! The compiler is smart enough to optimize the expression-bodied assignment into single statements.”

This tip seems to me a very good practice especially to avoid many lines of code and keep it clean and readable.


DateOnly and TimeOnly Types

Milan begins by introducing this tip with a question that I’m sure more than one of you have asked yourself:

“How many times did you only need to know about the Date component of a DateTime object?”

Previously this was not possible, but with the arrival of .NET 6, the Types DateOnly and TimeOnly were added.

And so Milan teaches us how to put them into practice:

DateOnly todaysDate = new DateOnly(22, 1, 20);

DateOnly currentUtcDate = DateOnly.FromDateTime(DateTime.UtcNow);
Enter fullscreen mode Exit fullscreen mode
// A couple constructors to choose from.
public TimeOnly(int hour, int minute)
public TimeOnly(int hour, int minute, int second)
public TimeOnly(int hour, int minute, int second, int millisecond)

TimeOnly nineInTheMorning = new TimeOnly(9, 0);

TimeOnly currentUtcTime = TimeOnly.FromDateTime(DateTime.UtcNow);
Enter fullscreen mode Exit fullscreen mode

However, Milan warns us that, for example PostgreSQL EF Core, already handles these new types without any problem. On the other hand, SQL Server does not at the moment:

“Unfortunately, it seems some EF Core providers — looking at you, SQL Server — still aren’t up to speed with the new types.”


Lazy Exception Caching

For this third tip, Milan tells us a bit about the .NET Lazy class. He wanted to focus on the exception caching behavior:

“If your initialization logic throws an exception, the Lazy instance will cache that exception. Subsequent access to the Lazy.Value property will throw that exception again.”

In addition, he warns that if we don’t really understand what is going on in that part of the code, we may have different kinds of problems in the future.

var exceptionTrappingLazy = new Lazy(() => CallExternalService());

try{
    // Accessing the Value property will execute CallExternalSe4rvice()
    // Now, imagine that the external service is down
    // The call to CallExternalService() throws an exception
    var lazyValue = exceptionTrappingLazy.Value;
}
catch {...}

try
{
    //Accesing the Value property again won't call CallExternalService()
    //It will throw the trapped exception again!
    var lazyValueAgain = exceptionTrappingLazy.Value;
}
catch{...}
Enter fullscreen mode Exit fullscreen mode

Finally, Milan reminds us that:

“The lazy instance can and will cache exceptions, and keep throwing them during its lifetime.”

After these 3 tips, let’s look at a series of tips also provided by Milan Jovanović. In these next tips Milan explains how to get the most out of the MinBy and MaxBy methods, which were introduced in .NET 6.

Let’s take a look at them!


How To Use MinBy and MaxBy LinQ Methods

In these examples Milan uses a couple of fruits and vegetables for a clear explanation. First, understand how MinBy and MaxBy work. For this we are going to use MinBy to find the smallest value and MaxBy to find the highest value. Let’s look at Milan’s first example:

public record Food (string Name, double Price);

var foodList = new List<Food>
{
    new("🍎", 1.15),
    new("🍌", 1.51),
    new("🥥", 2.99),
    new("🍋", 0.70),
    new("🥑", 9.13),
    new("🍄", 0.05),
};

//How do me find the cheapest food?

// How do we find the most expensive food?
Enter fullscreen mode Exit fullscreen mode

Find the smallest Value Object using MinBy

First it shows how it would look like in .NET 5 (without MinBy):

var cheapest = foodList.OrderBy(f => f.Price).List();
Enter fullscreen mode Exit fullscreen mode

Then, Milan shows how it would look like in .NET 6 (with MinBy):

var cheapest = foodList.MinBy(f => f.Price);
Enter fullscreen mode Exit fullscreen mode

In this case the result would be the mushroom “🍄” with 0.05 value (which apparently is not being affected by inflation in this example).

Sorry, let’s continue with the Milan examples:

Find the highest Value Object using MaxBy

First it shows how it would look like in .NET 5 (without MaxBy):

var mostExpensive = foodList
    .OrderByDescending(f => f.Price)
    .First();
Enter fullscreen mode Exit fullscreen mode

Then, Milan shows how it would look like in .NET 6 (with MaxBy):

var mostExpensive = foodList.MaxBy(f => f.Price);
Enter fullscreen mode Exit fullscreen mode

In this case the result would be the avocado “🥑” with 9.13 value (this one has been affected by inflation…).

With these best practices we can maintain a cleaner code even though Milan warns:

“Also, don’t try using them inside an EF Core query!

At the moment, they are not present in the EF provider.”

Keep it in mind developers!


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!

Top comments (1)

Collapse
bsantos96 profile image
bSantos96

First of all, thank you for the fantastic article, it will be so helpful for my future developments.
I think you have committed a mistake here in MinBy section:

var cheapest = foodList.OrderBy(f => f.Price).List();
Enter fullscreen mode Exit fullscreen mode

This will return a list and not a single element, which is what we want here. It should be instead:

var cheapest = foodList.OrderBy(f => f.Price).First();
Enter fullscreen mode Exit fullscreen mode

Head to your account's Settings to...

🌚 Enable dark mode
🔠 Change your default font
📚 Adjust your experience level to see more relevant content