Anti‑patterns typiques en C#

Liste détaillée des anti‑patterns les plus fréquents en C#, comment les reconnaître et comment les corriger.

1. Architecture & Conception

🔴 God Class / God Service

🔴 Service Locator

var service = ServiceLocator.Resolve<ICache>();

🔴 Primitive Obsession

public void CreateUser(string name, string email) { }

🔴 Feature Envy / Data Clumps

Groupe récurrent de paramètres → dépasser en record ou classe.

2. Asynchronisme & Threading

🔴 async void (hors événements UI)

async void DoWork() { await ... }

🔴 Bloquer async (Result, Wait)

var data = GetAsync().Result;

🔴 Task.Run dans ASP.NET

Pollution du thread pool → utiliser I/O async natif.

🔴 Pas d'utilisation d'IProgress<T>

Utiliser Invoke partout n’est plus nécessaire, Progress<T> publie automatiquement sur le contexte UI.

🔴 Mauvais locks

lock(this) { }
lock("string") { }

Utiliser un verrou privé :

private readonly object _gate = new();
lock(_gate) { }

3. Exceptions & Gestion d’erreurs

🔴 Exceptions avalées

try { } catch { }

🔴 Catch trop large

Préférer les exceptions spécifiques, utiliser when filters.

🔴 Exceptions utilisées comme flux normal

Préférer TryParse et équivalents.

4. Ressources & IDisposable

🔴 Oublier Dispose

var conn = new SqlConnection(cs);

Correction : using

using var conn = new SqlConnection(cs);

🔴 Mauvais pattern IDisposable

Utiliser le pattern standard + GC.SuppressFinalize(this).

🔴 Fuites d’événements

publisher.Changed += OnChanged;

5. API & Méthodes

🔴 Retourner null pour une collection

Correction : Array.Empty<T>() ou new List<T>().

🔴 Paramètres publics non validés

Correction : ArgumentNullException.ThrowIfNull(arg).

🔴 Equals / GetHashCode incohérents

Solution : utiliser des record pour gérer automatiquement.

6. LINQ, Performance & Style

🔴 Concaténation de chaînes dans une boucle

var s = "";
for(...) s += part;

Correction : StringBuilder.

🔴 LINQ abusif dans les hot paths

🔴 Magic strings / numbers

Correction : const, enum, nameof.

7. Internationalisation & Dates

🔴 DateTime.Now pour des données persistées

Correction : DateTimeOffset.UtcNow.

🔴 Formatage sans culture explicite

Utiliser CultureInfo.InvariantCulture ou culture choisie.

8. Tests & Maintenabilité

🔴 Code non testable (new partout)

🔴 Méthodes trop longues / multifonctions

Appliquer SRP, découper.

9. Détection automatique

10. Exemples avant / après

a) async void → async Task

// ❌
async void Process() { await DoAsync(); }

// ✅
async Task ProcessAsync() { await DoAsync(); }

b) .Result / .Wait → await

// ❌
var data = GetAsync().Result;

// ✅
var data = await GetAsync();

c) Magic strings → nameof

// ❌
throw new ArgumentNullException("user");

// ✅
throw new ArgumentNullException(nameof(user));