Instruction file imported from jtjaskulski/JJDevHub (
.cursor/rules/csharp.mdc). Copyright stays with the author.
C#
Typ i metoda robią jedną rzecz. Czytelnik nie schodzi w zagnieżdżenie.
- Jeden publiczny typ na plik. Namespace w klamrach (
namespace X.Y { … }), bez file-scoped (namespace X.Y;). Klasasealed. Dane bez zachowania torecord. - Od
sealedodstępują klasaabstract, klasastaticipartial class Program. Migracje EF (Migrations/,*.Designer.cs,*ModelSnapshot.cs) są poza tą regułą. - Drugi powód do zmiany to nowy typ. Długość jest zapachem, nie progiem.
- Kolejność składowych: pola, konstruktory, właściwości, metody. W grupie najpierw publiczne, potem prywatne, a statyczne przed instancją.
- Primary constructor zostaje na deklaracji typu. Dalsze konstruktory idą za polami.
- Długość metody jest zapachem. W szczęśliwym przebiegu jest jeden poziom wcięcia i wczesne wyjście.
try,finally,usingoraz jedna gałąź w pętli zostają. Kolejny poziom, który ma własny powód, wychodzi do metody. - Oczekiwany brak i błąd walidacji to wynik (
Resultsalbo własny typ), nie wyjątek.catchłapie konkretny typ i nic nie połyka. - Metoda
asyncbierzeCancellationTokeni podaje go tam, gdzie wywołanie ma ten parametr. Bez.Result,.Wait()iasync void. - Nullable jest włączone.
nullsprawdzasz na granicy, raz. Operator!nie wchodzi do kodu. - Zależności wchodzą primary constructorem. Prywatne pole istnieje tylko, gdy wartość żyje dłużej niż metoda.
- Nazwa mówi, co funkcja zwraca albo jaki skutek ma. Bez nowych skrótów (
usr,cfg,tmp),#regioni komentarza do następnej linii. Ustalone nazwy zostają:Id,Jwt,Http,Url. var, gdy typ widać po prawej (new, rzutowanie) albo nazwa metody go niesie. Przy prymitywie, liczbie i wywołaniu bez widocznego typu typ jest jawny.- Test ma jeden powód do padnięcia: arrange, act, assert. Kilka asercji jednego skutku to nadal jeden powód.
static async Task<IResult> GetNews(Guid id, AppDb database, CancellationToken cancellationToken)
{
var news = await database.News.FindAsync([id], cancellationToken);
if (news is not { Published: true })
{
return Results.NotFound();
}
return Results.Ok(news);
}
- Brak pustej linii na końcu pliku.
