1. Accueil
  2. Blog
  3. Pattern Using en C#
C# .Net

Pattern Using en C# : Gérer les ressources en toute sécurité

Le pattern using en C# transforme la gestion des ressources en automatisme sécurisé, éliminant définitivement les fuites mémoire et les oublis de libération de ressources.

Le problème : Les ressources oubliées

Dans nos applications dotnet, le nombre de ressources externes à gérer explose avec les avancées technologiques, la gestion manuelle des ressources peut rapidement devenir un cauchemar :

  • Fichiers non fermés qui bloquent l'accès
  • Connexions base de données qui restent ouvertes
  • Objets HttpClient non libérés
  • Fuites mémoire sur les applications qui s'exécutent longuement
  • Exceptions qui interrompent le flux et empêchent la libération

Exemple :

// ❌ Code dangereux - risque de fuite
var fileStream = new FileStream("data.txt", FileMode.Open);
var data = ReadData(fileStream);
// Oubli de fermer le stream !
// Le fichier reste verrouillé...

La solution magique & pratique : Le pattern using

Le pattern using garantit la libération automatique des ressources, même en cas d'exception. C'est votre femme de ménage personnelle pour les ressources !

// ✅ Code sécurisé avec using
using var fileStream = new FileStream("data.txt", FileMode.Open);
var data = ReadData(fileStream);
// La ressource est automatiquement libérée en fin de scope

Comment ça fonctionne ?

Le pattern using fonctionne avec toute classe implémentant IDisposable ou IAsyncDisposable :

// Syntaxe classique
using (var client = new HttpClient())
{
    var response = await client.GetAsync("https://api.example.com");
    // client.Dispose() appelé automatiquement
}

// Syntaxe moderne C# 8+ (using declaration)
using var client = new HttpClient();
var response = await client.GetAsync("https://api.example.com");
// client.Dispose() appelé en fin de bloc

Les différentes syntaxes

Le pattern using est un outil puissant pour gérer les ressources de manière efficace et sécurisée. Il permet de s'assurer que les ressources sont libérées correctement, même en cas d'erreur. Plusieurs syntaxes existent pour s'adapter à vos besoins et préférences.

Using statement (classique) : Contrôle précis du scope de libération

using (var connection = new SqlConnection(connectionString))
{
    connection.Open();

    // Utilisation de la connexion
} // connection.Dispose() appelé ici

Using declaration (moderne) : Plus concis, libération en fin de méthode

public async Task ProcessDataAsync()
{
    using var connection = new SqlConnection(connectionString);
    using var command = new SqlCommand(sql, connection);

    connection.Open();
    // Utilisation...

    // Toutes les ressources libérées ici automatiquement
}

Cas d'usage fréquents

Gestion de fichiers :

// Lecture sécurisée
using var reader = new StreamReader("config.json");
var content = await reader.ReadToEndAsync();

// Écriture sécurisée
using var writer = new StreamWriter("output.txt");
await writer.WriteLineAsync("Hello World!");

Appels HTTP :

using var client = new HttpClient();
var response = await client.GetAsync("https://api.example.com");
var json = await response.Content.ReadAsStringAsync();

Accès base de données :

using var connection = new SqlConnection(connectionString);
using var command = new SqlCommand("SELECT * FROM Users", connection);
connection.Open();
using var reader = command.ExecuteReader();
// Toutes les ressources SQL libérées automatiquement

Using asynchrone avec await using

Pour les ressources asynchrones, utilisez await using :

await using var stream = new FileStream("large-file.txt", FileMode.Open);
await using var reader = new StreamReader(stream);
var content = await reader.ReadToEndAsync();
// DisposeAsync() appelé automatiquement à la sortie du bloc

Implémentation personnalisée

Pour certains besoins de gestion de ressources, créez vos propres classes disposables en implémentant IDisposable ou IAsyncDisposable. Cela peut être utile pour encapsuler des transactions, des connexions ou d'autres ressources complexes.

public class DatabaseTransaction : IDisposable
{
    private readonly SqlTransaction _transaction;
    private bool _disposed = false;

    public DatabaseTransaction(SqlTransaction transaction)
    {
        _transaction = transaction;
    }

    public void Commit() => _transaction.Commit();
    public void Rollback() => _transaction.Rollback();

    public void Dispose()
    {
        if (!_disposed)
        {
            _transaction?.Dispose();
            _disposed = true;
        }
    }
}

// Utilisation
using var transaction = new DatabaseTransaction(sqlTransaction);
try
{
    // Opérations...
    transaction.Commit();
}
catch
{
    transaction.Rollback();
    throw;
}

Bonnes pratiques

  • Préférez using var pour plus de lisibilité
  • Utilisez await using pour les ressources asynchrones
  • N'oubliez pas le pattern dans vos API : laissez l'appelant gérer la ressource
  • Testez vos implémentations IDisposable avec des using
Implémenté correctement, il devient impossible d'oublier de libérer une ressource avec le pattern using !

Conclusion

Le pattern using transforme la gestion des ressources en automatisme sécurisé, éliminant les fuites mémoire !

En adoptant systématiquement le pattern using dans vos applications .NET, vous garantissez une gestion des ressources robuste et prévisible. C'est un investissement minimal pour un gain énorme en stabilité et en maintenabilité.

Et si on se rencontrait,
pour de vrai ?

Laissez votre message après le clic !
Vague jaune décorative du footer Black Blue Bees