În versiunile anterioare de C#, injectarea dependențelor într-un serviciu necesita o cantitate frustrantă de cod boilerplate: declararea câmpurilor private `readonly`, scrierea constructorului cu aceiași parametri și atribuirea manuală `this._repo = repo`.
Începând cu C# 12 (.NET 8), funcționalitatea de Constructori Primari (Primary Constructors) a fost extinsă de la tipurile `record` la toate clasele și structurile standard. Parametrii sunt declarați direct între parantezele rotunde ale numelui clasei.
Acești parametri devin automat accesibili pe tot parcursul corpului clasei (în metode, proprietăți și funcții interne), reducând dimensiunea claselor de servicii cu peste 40% și menținând codul curat și extrem de ușor de citit.
Sintaxă, opțiuni și concepte cheie
| Opțiune / Concept | Descriere practică |
|---|---|
public class Nume(Parametri) |
Sintaxa prin care parametrii de inițializare sunt definiți direct pe antetul tipului. |
Field Capture |
Compilatorul capturează automat parametrii utilizați în metode fără a fi nevoie de variabile explicite. |
Base Constructor Chaining |
Transmiterea ușoară către clasa de bază prin sintaxa `class Copil(int id) : Parinte(id)`. |
Dependency Injection Cleanliness |
Modelul ideal pentru injectarea automată a serviciilor în arhitecturi ASP.NET Core. |
Exemple practice și cod
Exemplul 1: Comparativ: Clasă de serviciu în C# clasic vs. C# 12 cu Constructor Primar
Reducerea masivă a codului repetitiv.
// --- ABORDAREA VECHE (C# 11 și anterior) ---
public class UserServiceOld
{
private readonly IUserRepository _repo;
private readonly ILogger _logger;
public UserServiceOld(IUserRepository repo, ILogger logger)
{
_repo = repo;
_logger = logger;
}
public async Task GetAsync(int id) => await _repo.FindByIdAsync(id);
}
// --- ABORDAREA MODERNĂ C# 12 / .NET 8 ---
public class UserService(IUserRepository repo, ILogger logger)
{
public async Task GetAsync(int id)
{
logger.LogInformation("Căutare utilizator {Id}", id);
return await repo.FindByIdAsync(id);
}
}
Rezultat & Impact
Cod de 3 ori mai compact, la fel de sigur și complet compatibil cu Dependency Injection.
Greșeli frecvente și bune practici
- Mutarea accidentală a valorii unui parametru de constructor primar în interiorul unei metode dacă parametrul nu este marcat ca `readonly`; în clase standard, parametrii capturați sunt mutabili.
- Declararea redundantă a unui câmp privat `readonly` cu același nume, anulând avantajul sintactic al constructorului primar.