Dot.Blog

Consulting DotNet C#, XAML, WinUI, WPF, MAUI, IA

Utiliser record, record struct et l’immutabilité en C# moderne

L’immutabilité est une pierre angulaire des applications robustes, particulièrement dans les architectures modernes (fonctionnelles, distribuées, multi-threadées). Avec record et record struct, C# permet de modéliser des objets immuables simplement et efficacement.

Dans cet article, je vous montre comment exploiter ces types pour construire des modèles de données propres, prévisibles et faciles à manipuler.

📦 Pourquoi préférer l’immutabilité ?

  • Empêche les effets de bord
  • Facilite le débogage et les tests
  • Rend les données thread-safe
  • Représente fidèlement des états figés (DTO, snapshots)

🔖 record : le modèle de données immuable de référence

public record Person(string FirstName, string LastName);

Avantages :

  • Propriétés init seulement
  • Supporte l’opérateur with
  • Comparaison par valeur (et non par référence)
var p1 = new Person("Alice", "Martin");
var p2 = p1 with { FirstName = "Bob" };
Console.WriteLine(p1); // Person { FirstName = Alice, LastName = Martin }
Console.WriteLine(p2); // Person { FirstName = Bob, LastName = Martin }

💡 record struct : version plus légère, sur la stack

Depuis C# 10, vous pouvez utiliser :

public readonly record struct Point(int X, int Y);
  • Immuable par défaut
  • Moins d’allocations, fonctionne sur la stack
  • Idéal pour les structures géométriques, vecteurs, cases, etc.

⚠️ Différences entre record, class, struct, record struct

Type

Référence ou valeur ?

Immuable ?

Comparaison

class

Référence

Non (par défaut)

Par référence

struct

Valeur

Non (par défaut)

Par valeur

record

Référence

Oui (init)

Par valeur

record struct

Valeur

Oui (init)

Par valeur

🧪 Exemple avancé : créer un modèle métier

public record Invoice(int Id, DateTime Date, decimal Amount);
var original = new Invoice(1, DateTime.Today, 100m);
var corrected = original with { Amount = 120m };

Console.WriteLine(original);  // Invoice { Id = 1, Date = ..., Amount = 100 }
Console.WriteLine(corrected); // Invoice { Id = 1, Date = ..., Amount = 120 }

🧠 Et les init properties ?

Même avec class, vous pouvez forcer l’immuabilité à l’initialisation :

public class User
{
    public string Name { get; init; }
    public DateTime Created { get; init; } = DateTime.Now;
}

var user = new User { Name = "Claire" };

Mais cela n’offre ni with, ni égalité par valeur.

✅ Bonnes pratiques

  • Préférez record pour vos modèles métier simples
  • Utilisez record struct pour les structures performantes sans GC
  • Combinez avec with, init, readonly pour des objets solides et testables
  • Pensez au pattern matching, très efficace avec les record

🔚 Conclusion

Les record et record struct modernisent la façon de penser vos modèles en C#. En misant sur l’immutabilité, vous construisez des applications plus maintenables, moins sujettes aux bugs et prêtes pour le multithreading.

Par expérience je sais qu'il n'est pas toujours facile de penser immutabilité, cela se rapproche beaucoup plus de l'esprit de la programmation fonctionnelle comme le permet F# sur lequel j'ai produit une série d'article à sa sortie. Et je sais que ce type de langage (et leur approche) obtient souvent un succès d'estime inversement proportionnel à leur adoption... Tout le monde en parle mais personne ne s'en sert, en tout cas dans de l'entreprise, des Apps de type LOB.

Sans basculer totalement dans le côté obscur de la force de F#, essayez d'introduire plus de fonctionnel dans votre façon de développer. Et cela peut commencer humblement par l'utilisation des types immutables...

Stay Tuned !

Faites des heureux, PARTAGEZ l'article !