Galactic-Shrine C# Coding Standard
Version: 1.0.0
Auteur / Author: ⋞Galactic-Shrine⋟
Portée / Scope: Projets C# / .NET / Class Libraries / SDKs / CLI / Applications Desktop / APIs / Services / Tooling
1. Objectif
Ce standard définit la manière d’écrire le code C# dans les projets Galactic-Shrine.
Il a pour objectifs :
- d’uniformiser le style C# dans les bibliothèques et applications ;
- d’imposer une convention de nommage claire et stable ;
- d’intégrer explicitement la règle Galactic-Shrine
PascalCasepour propriétés, paramètres et méthodes ; - de garder un code compatible avec un usage industriel et maintenable.
2. Principes généraux
Le code C# Galactic-Shrine doit être :
- lisible ;
- explicite ;
- idiomatique quand cela ne contredit pas les décisions Galactic-Shrine ;
- robuste ;
- facile à refactoriser.
Le code doit privilégier :
- des types courts et spécialisés ;
- des dépendances injectées explicitement ;
- des signatures nettes ;
- une nullabilité traitée consciemment ;
- des exceptions réservées aux erreurs réellement exceptionnelles ou contractuelles.
3. Décisions officielles Galactic-Shrine pour C#
Décisions officielles :
- propriétés en
PascalCase; - paramètres en
PascalCase; - méthodes en
PascalCase; - classes, records, structs, enums et delegates en
PascalCase; - champs privés en
_PascalCase; - interfaces en
IPascalCase; - variables locales en
PascalCase; - fichiers nommés selon le type principal ;
- activer et respecter la nullabilité quand elle est disponible ;
- éviter les abréviations opaques.
Exemple :
public sealed class UserProfileService
{
private readonly IUserRepository _UserRepository;
public UserProfileService(IUserRepository UserRepository)
{
ArgumentNullException.ThrowIfNull(UserRepository);
_UserRepository = UserRepository;
}
public async Task<UserProfile?> GetProfileAsync(Guid UserId, CancellationToken CancellationToken)
{
return await _UserRepository.FindProfileAsync(UserId, CancellationToken);
}
}
4. Convention de nommage
- namespace : stable, hiérarchique, orienté domaine ou couche ;
- classe / record / struct / enum :
PascalCase; - interface :
IPascalCase; - propriété :
PascalCase; - méthode :
PascalCase; - paramètre :
PascalCase; - variable locale :
PascalCase; - champ privé :
_PascalCase; - champ
const:PascalCase; - champ
static readonly:PascalCaseou_PascalCaseselon visibilité, mais rester uniforme dans le projet.
À éviter :
obj,mgr,svc,tmp,data2sans contexte ;- les noms qui décrivent la technique sans l’intention ;
- des suffixes artificiels partout.
5. Structure recommandée d’un fichier C#
Ordre recommandé :
- en-tête légal si requis ;
using;namespace;- type principal ;
- types internes liés uniquement si cela reste lisible.
Ordre recommandé dans un type :
- constantes ;
- champs statiques ;
- champs d’instance ;
- constructeurs ;
- propriétés ;
- méthodes publiques ;
- méthodes protégées ;
- méthodes privées ;
- types imbriqués si vraiment nécessaires.
Éviter :
- plusieurs gros types publics sans lien dans le même fichier ;
- des régions utilisées pour masquer un manque de structure ;
- des méthodes privées éparpillées sans ordre.
6. Style d’écriture
6.1 Accolades et blocs
Toujours utiliser des blocs explicites pour if, else, for, foreach, while, using, sauf cas ultra-triviaux validés par le projet.
6.2 Retours anticipés
Préférer un retour anticipé lorsqu’il réduit l’imbrication et clarifie le contrat.
6.3 LINQ
Utiliser LINQ lorsqu’il améliore clairement la lecture.
Éviter les chaînes LINQ trop denses ou difficiles à déboguer.
6.4 var
Utiliser var lorsque le type est évident à la lecture immédiate.
Sinon, préférer le type explicite.
6.5 async/await
- suffixer les méthodes asynchrones par
Async; - propager
CancellationTokenlorsque pertinent ; - éviter
async voidsauf gestionnaires d’événements ; - ne pas bloquer artificiellement sur du code asynchrone.
7. Règles spécifiques C#
- utiliser
ArgumentNullException.ThrowIfNull(...)aux frontières appropriées ; - marquer
sealedlorsqu’un type n’a pas vocation à être hérité ; - préférer
enumexplicites et lisibles ; - privilégier
recordseulement si la sémantique valeur est réelle ; - limiter les extension methods aux cas légitimes ;
- éviter les classes statiques utilitaires trop larges ;
- ne pas exposer de collection mutable si une abstraction plus sûre convient ;
- rester prudent avec la réflexion, le
dynamicet les conversions implicites coûteuses.
8. Gestion des erreurs et robustesse
- lancer des exceptions avec un message exploitable ;
- ne pas avaler une exception sans traitement ou journalisation pertinente ;
- utiliser des types de résultat dédiés quand l’absence d’un élément est un cas normal ;
- documenter les contrats importants côté API publique ;
- séparer les validations d’entrée, les erreurs métier et les erreurs d’infrastructure.
9. Types d’éléments à revoir en priorité
Relire en priorité :
- services applicatifs ;
- factories, builders, providers ;
- repositories et accès externes ;
- modèles exposés publiquement ;
- code asynchrone ;
- sérialisation / désérialisation ;
- gestion des options et configuration ;
- utilitaires partagés.
10. Exemple complet recommandé
namespace GalacticShrine.Users;
public sealed class UserProfileService
{
private readonly IUserRepository _UserRepository;
private readonly IClock _Clock;
public UserProfileService(IUserRepository UserRepository, IClock Clock)
{
ArgumentNullException.ThrowIfNull(UserRepository);
ArgumentNullException.ThrowIfNull(Clock);
_UserRepository = UserRepository;
_Clock = Clock;
}
public async Task<UserProfileResult> UpdateDisplayNameAsync(
Guid UserId,
string DisplayName,
CancellationToken CancellationToken)
{
ArgumentNullException.ThrowIfNull(DisplayName);
string NormalizedDisplayName = DisplayName.Trim();
if (NormalizedDisplayName.Length == 0)
{
return UserProfileResult.Invalid("DisplayName cannot be empty.");
}
UserProfile? ExistingProfile = await _UserRepository.FindProfileAsync(UserId, CancellationToken);
if (ExistingProfile is null)
{
return UserProfileResult.NotFound();
}
ExistingProfile.UpdateDisplayName(NormalizedDisplayName, _Clock.UtcNow);
await _UserRepository.SaveAsync(ExistingProfile, CancellationToken);
return UserProfileResult.Success(ExistingProfile);
}
}
11. Décision officielle recommandée
Standard officiel recommandé pour Galactic-Shrine C# :
- utiliser
PascalCasepour propriétés, paramètres, méthodes et variables locales ; - utiliser
_PascalCasepour les champs privés ; - garder un type principal par fichier ;
- écrire des méthodes courtes et testables ;
- respecter la nullabilité et les contrats d’erreur ;
- utiliser
Asyncpour les méthodes asynchrones.
12. Résumé exécutable
À appliquer dans tous les projets C# Galactic-Shrine :
PascalCasepour propriétés, paramètres, méthodes et variables locales ;_PascalCasepour les champs privés ;IPascalCasepour les interfaces ;- un type principal par fichier ;
- validation explicite des entrées ;
async/awaitpropre, avecCancellationTokenquand nécessaire ;- pas de classes “god object”.