Dot.Blog

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

ref struct et readonly struct en C# : performances et pièges à connaître

Les types struct sont historiquement associés à la légèreté. Mais avec les mots-clés ref struct et readonly struct, C# permet d'aller encore plus loin dans l'optimisation de la mémoire et des performances. Ce guide pratique vous explique leur utilité, leurs limites et comment les utiliser efficacement en .NET 9.

🔧 Pourquoi ref struct ?

Un ref struct est un type valeur structuré pour vivre exclusivement sur la pile (stack). Cela permet :

  • D'éviter l'allocation sur le heap
  • D'éliminer la pression sur le garbage collector
  • De garantir des accès très rapides et localisés

Ce mot-clé est notamment utilisé pour :

  • Span<T>
  • ReadOnlySpan<T>
  • Utf8JsonReader
  • StreamReader.ReadOnlySpan<char>

🚫 Contraintes d’un ref struct

Un ref struct ne peut pas :

  • Être capturé dans un lambda ou une closure
  • Être utilisé dans un champ d’une classe
  • Être boxé (pas de conversion vers object)
  • Être retourné de manière async

Ces règles visent à garantir l’intégrité de la pile.

✅ Exemple : définir un ref struct personnalisé

ref struct LineView
{
    private ReadOnlySpan<char> _span;
    public LineView(ReadOnlySpan<char> span) => _span = span;

    public ReadOnlySpan<char> FirstWord()
    {
        int index = _span.IndexOf(' ');
        return index >= 0 ? _span[..index] : _span;
    }
}

// Utilisation
string phrase = "Hello Semantic Kernel";
var view = new LineView(phrase);
Console.WriteLine(view.FirstWord().ToString());

Ici, aucun objet n'est alloué. Tout se fait sur la stack.

🔒 readonly struct : pour l’immutabilité et la performance

Un readonly struct garantit que ses champs ne peuvent pas être modifiés après construction.

Avantages :

  • Empêche les mutations accidentelles
  • Active des optimisations du JIT
  • Rend le struct plus fiable dans les contextes multi-thread

Exemple :

readonly struct Point2D
{
    public int X { get; }
    public int Y { get; }

    public Point2D(int x, int y) => (X, Y) = (x, y);
    public double Norme() => Math.Sqrt(X * X + Y * Y);
}

Ce struct peut être passé dans des threads sans risque de corruption d’état.

💡 Et readonly ref struct ?

C’est simplement la combinaison des deux : un type stack-only et immutable.

Utile pour des analyseurs, des wrappers Span<T>, des vues de mémoire temporaires.

⚠️ Cas à éviter ou à surveiller

  • Ne pas exposer un ref struct dans une API publique si le consommateur ne contrôle pas sa durée de vie
  • Ne pas tenter de le sérialiser ou de le stocker dans une collection
  • Attention aux erreurs de portée : un Span<T> créé dans une méthode ne peut pas survivre en dehors

🧠 Scénarios utiles

  • Traitement de fichiers ligne par ligne sans allocation
  • Wrapping léger de buffers pour parsing rapide
  • Traitement de texte haute performance
  • Applications temps réel ou embarquées

🔚 Conclusion

Les ref struct et readonly struct permettent d’écrire un code C# ultra-performant et sûr en évitant les pièges du heap. Leur bonne utilisation peut transformer le comportement d’une application dans des traitements intensifs.

Avec .NET 9 et les bibliothèques modernes (par exemple System.Text.Json), ces types sont devenus incontournables pour les développeurs soucieux de performance et de robustesse.

Bien entendu ces améliorations ne feront pas tout et ne rendrons pas un âne un cheval de course, il faut aussi faire attention aux accès asynchrone aux devices ou SGBD externes, mais aussi aux allocations mémoires implicites, plus sournoises. Développer efficace n'est pas qu'une question de recettes c'est aussi et avant tout une maîtrise des détails, partout, à chacun coin de code. Un jeu de patience et de perspicacité qui vise la vitesse et l'économie des ressources...

Stay Tuned !

Faites des heureux, PARTAGEZ l'article !