Advertisement
Search  
Always will be ready notify the world about expectations as easy as possible: job change page
Feb 1

Mastering C#: Tips for performance, LINQ, DTOs, and more

Author:
Source:
Views:
1186

Performance, LINQ, DTO

Introduction

Welcome to the world of C#! Whether you’re a seasoned developer or just starting your programming journey, the power and versatility of C# can elevate your coding experience. In this article, we’ll explore a curated collection of tips and tricks to enhance your proficiency in C#. From optimizing code performance to leveraging advanced language features, these tips are designed to empower you in writing cleaner, more efficient, and robust C# code. Let’s dive into the intricacies of C# and uncover some valuable insights that will undoubtedly sharpen your programming skills.

1. Choosing between Any and Count

  • Use Any when you are interested in whether at least one element meets a certain condition, and you don't need to know the count.
  • Use Count when you need to know the number of elements that meet a specific condition.

Any:

  1. Any is used to determine whether any elements in a sequence satisfy a specific condition.
  2. It returns a Boolean indicating whether there are any elements in the collection.
  3. It stops iterating through the collection as soon as it finds the first matching element.
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
bool anyGreaterThanThree = numbers.Any(x => x > 3);

Count:

  1. Count is used to get the number of elements in a sequence that satisfy a specific condition.
  2. It counts all the elements in the collection that meet the specified criteria.
  3. It iterates through the entire collection to count all matching elements.
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
int countGreaterThanThree = numbers.Count(x => x > 3);

2. Avoid using ToUpper / ToLower when comparing strings

When comparing strings is valid, especially when you want to perform case-insensitive comparisons. Using ToUpper() or ToLower() can be less efficient because it involves creating new string objects.

The second approach is, using string.Equals with StringComparison.OrdinalIgnoreCase, is a more efficient and idiomatic way to achieve case-insensitive string comparison in .NET. This approach avoids creating additional string objects and provides better performance.

public bool AreStringsEqual(string first, string second)
{
    // slow
    return first.ToUpper() == second.ToUpper();
}

public bool AreStringsEqual(string first, string second)
{
    // fast
    return string.Equals(first, second, StringComparison. OrdinalIgnoreCase);
}

3. Multiple OrderBy() vs ThenBy()

OrderBy:

  1. The OrderBy method is used to sort the elements of a sequence in ascending order based on a specified key.
  2. It returns a new sequence in which the elements are sorted based on the specified key.
  3. If you want to sort a collection based on multiple criteria, you should use OrderBy for the primary sorting criterion.
List<Person> people = GetPeople();

var sortedPeople = people.OrderBy(person => person.LastName);

ThenBy:

  1. The ThenBy method is used for secondary sorting. It is applied to the result of OrderBy and further refines the order of elements based on another key.
  2. It is used when you have already sorted the collection using OrderBy, and you want to add additional sorting criteria.
List<Person> people = GetPeople();

var sortedPeople = people
    .OrderBy(person => person.LastName)
    .ThenBy(person => person.FirstName);

Example with Multiple OrderBy:

You can use multiple OrderBy clauses to achieve the same result as OrderBy and ThenBy. However, using ThenBy is generally more readable and can be more efficient.

List<Person> people = GetPeople();

var sortedPeople = people
    .OrderBy(person => person.LastName)
    .OrderBy(person => person.FirstName); // This is less readable and can be less efficient

When to use each:

  • Use OrderBy for the primary sorting criterion.
  • Use ThenBy for secondary, tertiary, and subsequent sorting criteria.
  • Use multiple OrderBy clauses only when you want to replace the existing order with a new one.

Summary:

  • OrderBy: Use for the primary sorting criterion.
  • ThenBy: Use for secondary and subsequent sorting criteria.
  • Multiple OrderBy: Less common; use only when you want to replace the existing order.

4. Strings should not be concatenated using ‘+’ in a loop

Strings are immutable, which means that once a string object is created, it cannot be modified. When you concatenate strings using the ‘+’ 𝗼𝗽𝗲𝗿𝗮𝘁𝗼𝗿 in a loop, a new string object is created at each iteration, and the previous objects are discarded. This can lead to performance issues, especially when dealing with large strings or a large number of iterations.

A more efficient approach to string concatenation in C# is to use the 𝗦𝘁𝗿𝗶𝗻𝗴𝗕𝘂𝗶𝗹𝗱𝗲𝗿 𝗰𝗹𝗮𝘀𝘀, which is designed for efficiently building strings in a loop. StringBuilder allows you to append strings without creating new objects each time, which leads to better performance.

𝗦𝘁𝗿𝗶𝗻𝗴𝗕𝘂𝗶𝗹𝗱𝗲𝗿 is more useful when dealing with large strings or a large number of iterations and when we have an unknown amount of strings.

By using 𝗦𝘁𝗿𝗶𝗻𝗴𝗕𝘂𝗶𝗹𝗱𝗲𝗿, you can significantly reduce memory allocations and improve the performance of your code when you need to concatenate strings in a loop. It is a best practice to use StringBuilder when working with dynamic string building operations.

// + operator
string result = string.Empty;
foreach (var str in arrayOfStrings)
{
    result += str;
}

// builder
StringBuilder builder = new StringBuilder();
foreach (var str in arrayOfStrings)
{
    builder.Append(str);
}
string result = builder.ToString();

5. AsNoTracking

In Entity Framework Core, the AsNoTracking method is often used to improve performance when retrieving entities from the database. The AsNoTracking method informs EF Core that the entities being queried don't need to be tracked for changes, which can result in faster queries and reduced memory consumption. Here's a brief explanation of the improvement:

public List<User> GetUsers()
{
    // Slow - Tracking entities for changes
    return db.Users.ToList();
}

public List<User> GetUsers()
{
    // Fast - Not tracking entities for changes
    return db.Users.AsNoTracking().ToList();
}

Adding AsNoTracking indicates to EF Core that the entities retrieved should not be tracked. This can significantly improve the performance of the query, especially when dealing with large result sets, as it avoids the overhead of change tracking.

6. Class vs Record

When using Data Transfer Objects (DTOs) in C#, the choice between using classes or records depends on your specific requirements and the characteristics of the data you’re transferring. Both classes and records can be used for defining DTOs, but each has its own strengths and use cases. Let’s explore the considerations for using classes and records for DTOs.

Using a Class for DTO:

public class ProductDTO
{
    public string Name { get; set; }
    public double Price { get; set; }
    public int StockQuantity { get; set; }
}

Pros:

  • Full control over mutability: You can use properties with getters and setters, giving you the flexibility to make properties mutable if needed.
  • Extensibility: You can add methods, implement interfaces, and provide custom behavior as necessary.

Cons:

  • Boilerplate code: More lines of code are required for property declarations, getters, setters, and potentially other methods.

Using a Record for DTO:

public record ProductDTO(
    string Name,
    double Price,
    int StockQuantity);

Pros:

  • Concise syntax: Records provide a concise and expressive way to define immutable DTOs with minimal boilerplate code.
  • Automatic value-based equality: Records automatically generate Equals, GetHashCode, and ToString methods based on the property values.

Cons:

  • Limited mutability: Records are inherently designed for immutability, and their properties are implicitly read-only. While you can use init in the property declaration to set values during initialization, the properties remain read-only once set.

Choosing between Class and Record for DTO:

Use a Class when:

  • You need full control over mutability.
  • You want to provide custom behavior through methods.
  • You need to implement interfaces or provide custom serialization logic.

Use a Record when:

  • You are modeling immutable data transfer objects.
  • You want a concise syntax for defining DTOs.
  • Value-based equality is beneficial for your use case.𝗨𝘀𝗲 ‘𝗠𝗶𝗻𝗕𝘆’ 𝗼𝗿

7. MinBy() and MaxBy() instead of ordering and taking ‘First’ or ‘Last’

In LINQ, there isn’t a direct MinBy or MaxBy method, but you can achieve similar functionality by using the OrderBy or OrderByDescending methods along with the First or Last method. However, if you want to avoid sorting the entire collection and only find the minimum or maximum element based on a specific criteria, you can create extension methods for MinBy and MaxBy.

The MinBy and MaxBy extension methods offer advantages over sorting the entire collection when you need to find the minimum or maximum element based on a specific key. These advantages include increased efficiency, optimized key comparison, lazy evaluation for better performance, adaptability to different collections, customization through key selector functions, and avoidance of sorting overhead.

List<int> numbers = new List<int> { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 };

// Traditional Approach using OrderBy and First
var orderedNumbers = numbers.OrderBy(x => x);
int minNumberTraditional = orderedNumbers.First();
int maxNumberTraditional = orderedNumbers.Last();

// Using MinBy and MaxBy extension methods
int minNumber = numbers.MinBy(x => x);
int maxNumber = numbers.MaxBy(x => x);
Similar
Dec 26, 2022
Author: Mahesh Chand
IntroductionDo you find yourself not having enough time in a day? Why isn't the work getting done? And why is it taking so long? If these questions sound familiar, you're not alone. Productivity is very important also while working from home....
May 29, 2023
Maximizing performance in asynchronous programmingTask and Task<TResult>The Task and Task<TResult> types were introduced in .NET 4.0 as part of the Task Parallel Library (TPL) in 2010, which provided a new model for writing multithreaded and asynchronous code.For demonstration purposes, let’s...
Nov 27, 2023
Author: Juldhais Hengkyawan
Use the Bogus library to generate and insert 1 million dummy product data into the SQL Server databaseWe need to create 1 million dummy product data into the SQL Server database, which can be used for development or performance testing...
15 марта
Автор: Рустем Галиев
Blazor — это технология, позволяющая создавать клиентские веб-приложения с использованием C# и .NET, а не JavaScript. Blazor может запускать ваш код одним из двух способов. Blazor WebAssembly выполняет код C# на стороне клиента в любом современном браузере, поддерживающем WebAssembly. Blazor...
Send message
Email
Your name
*Message


© 1999–2024 WebDynamics
1980–... Sergey Drozdov
Area of interests: .NET Framework | .NET Core | C# | ASP.NET | Windows Forms | WPF | HTML5 | CSS3 | jQuery | AJAX | Angular | React | MS SQL Server | Transact-SQL | ADO.NET | Entity Framework | IIS | OOP | OOA | OOD | WCF | WPF | MSMQ | MVC | MVP | MVVM | Design Patterns | Enterprise Architecture | Scrum | Kanban