1. Problème de noms identiques : champ, propriété, paramètre
Les débutants se retrouvent souvent dans une situation où les noms des propriétés, des paramètres du constructeur et des champs privés sont les mêmes. Le compilateur ne râle pas, mais le résultat peut ne pas être celui attendu.
Exemple
public class Student
{
private string name;
public Student(string name)
{
name = name; // "On dirait que tout est bon..."
}
public void PrintName()
{
Console.WriteLine(name);
}
}
Qu'est-ce qui va se passer ? La méthode PrintName() n'aura rien à afficher : le champ privé name restera null ! Tout ça parce qu'à l'intérieur du constructeur, name = name; bosse avec le paramètre local, pas avec le champ de la classe.
Comment éviter
Utilise le mot-clé this pour accéder aux champs/propriétés de la classe :
public Student(string name)
{
this.name = name; // Là c'est bon !
}
Note : Rider et d'autres IDE vont t'aider à repérer ce genre d'erreurs — écoute leurs suggestions !
2. Constructeur par défaut manquant : quand est-ce qu'il faut ?
Si tu déclares au moins un constructeur custom, le compilateur ne crée plus de constructeur "vide" par défaut. Ça cause souvent des bugs, surtout quand tu veux créer un objet sans paramètres.
Exemple
public class Book
{
public string Title { get; set; }
// Constructeur déclaré explicitement
public Book(string title)
{
Title = title;
}
}
var book = new Book(); // Compilateur : "Bip-bip ! Pas de constructeur sans paramètres !"
Si tu veux pouvoir créer une instance avec ou sans paramètres, pense à ajouter explicitement le constructeur qu'il faut :
public Book() { }
public Book(string title)
{
Title = title;
}
3. Modificateurs d'accès : la vie privée des gens publics
Erreur classique des débutants — oublier les modificateurs d'accès. Par défaut, les champs et méthodes d'une classe sont en private, et les membres d'une struct aussi en private. Si tu oublies ou utilises par défaut, tu risques de ne pas pouvoir utiliser les propriétés ou méthodes voulues en dehors de la classe.
Exemple
public class Animal
{
string name; // private par défaut
public void PrintName()
{
Console.WriteLine(name);
}
}
var animal = new Animal();
animal.name = "Kitty"; // Erreur de compilation !
Le compilateur ne te laissera pas accéder à un membre privé. Il vaut mieux indiquer explicitement le modificateur :
public string Name;
ou
private string name;
Pour un accès plus propre, utilise des propriétés :
public string Name { get; set; }
4. Champ non initialisé : le piège du null
Un piège super courant — un champ de classe pas initialisé. C'est surtout dangereux si le champ est utilisé dans des méthodes appelées avant une initialisation explicite.
Exemple
public class Cat
{
public string Name;
public void SayHello()
{
Console.WriteLine($"Miaou ! La longueur du nom est {Name.Length} lettres !"); // Possible NullReferenceException
}
}
var cat = new Cat();
cat.SayHello(); // Quelle tragédie !
La variable Name vaut null, et essayer d'accéder à Length va donner un NullReferenceException. Fais gaffe à l'état des objets après leur création !
Astuce : Utilise les constructeurs pour forcer la saisie des champs importants, et marque les propriétés comme obligatoires (dans les nouveaux C# - avec required).
5. Récursion infinie dans les propriétés auto : erreur de copier-coller
Parfois, on écrit une propriété à la main et on se plante — genre dans le getter ou setter, on fait référence à la propriété elle-même (au lieu du champ privé), ce qui boucle à l'infini.
Exemple
public class Dog
{
public int Age
{
get { return Age; } // Oups !
set { Age = value; } // Oups-oup !
}
}
Ce code, à chaque appel de Age, va s'appeler lui-même... à l'infini (jusqu'à ce que la stack explose — auto-cannibalisme récursif).
Comment faire bien
Utilise un champ privé séparé :
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
Ou alors, utilise une auto-propriété :
public int Age { get; set; }
6. Incohérence des noms
En programmation, il faut être soigneux avec la casse et les noms. C# est Case-Sensitive, donc Name, name, NAME — ce sont trois identifiants différents.
Aussi, si tu changes le nom d'un champ ou d'une propriété, assure-toi de le changer partout ! Rider peut t'aider à refactorer, mais il ne protège pas toujours des fautes de frappe (surtout si les noms se ressemblent).
7. Utilisation du mauvais modificateur (static/instance)
Parfois, les débutants confondent méthodes d'instance et méthodes statiques. Le souci arrive quand tu veux accéder à un champ/méthode d'une façon non autorisée par la syntaxe C#.
Exemple
public class MathHelper
{
public static int Add(int a, int b) => a + b;
public int Multiply(int a, int b) => a * b;
}
var sum = MathHelper.Add(2, 3); // OK
var mul = MathHelper.Multiply(2, 3); // Erreur !
La méthode Multiply n'est pas statique, tu ne peux pas l'appeler via le nom de la classe sans créer d'objet :
var helper = new MathHelper();
var mul = helper.Multiply(2, 3); // Là c'est bon
8. Erreurs lors de l'héritage du constructeur
Si ta classe hérite d'une autre, n'oublie pas que la classe de base peut exiger des paramètres dans son constructeur.
Exemple
public class Animal
{
public string Name;
public Animal(string name)
{
Name = name;
}
}
public class Dog : Animal
{
public Dog() { } // Erreur : la classe de base veut name !
}
Le compilateur ne te laissera pas déclarer ce constructeur. Il faut appeler explicitement le constructeur de la base :
public class Dog : Animal
{
public Dog(string name) : base(name) { }
}
9. Oubli d'implémenter tous les membres de l'interface
Si ta classe implémente une interface mais n'a pas implémenté toutes ses méthodes — tu auras une erreur de compilation : "La classe n'implémente pas complètement l'interface".
Exemple
public interface IWalker
{
void Walk();
void Run();
}
public class Turtle : IWalker
{
public void Walk()
{
Console.WriteLine("Lentement mais sûrement...");
}
// Oups ! On a oublié Run !
}
L'IDE va râler, et Turtle ne compile pas tant que tu n'as pas implémenté toutes les méthodes de l'interface.
10. Utilisation d'objets non initialisés
En C#, les objets sont créés explicitement avec new. Si tu déclares juste une variable de référence sans lui assigner d'objet — elle vaut null. Si tu essaies d'accéder à ses champs/méthodes, tu auras le fameux NullReferenceException.
Exemple
Student student;
student.PrintName(); // Surprise !
Il faut absolument initialiser l'objet :
Student student = new Student("Alice");
student.PrintName();
11. Erreur : champs publics au lieu de propriétés
Vieux "anti-pattern" : déclarer tous les champs d'une classe en public. Pourquoi c'est nul ? Les champs ne sont pas protégés, aucun contrôle sur les changements, encapsulation cassée !
Exemple
public class Car
{
public int speed; // Ne fais pas ça !
}
Mieux vaut utiliser des propriétés :
public class Car
{
public int Speed { get; set; }
}
Les propriétés permettent d'ajouter des vérifs, de la logique, des restrictions :
private int speed;
public int Speed
{
get { return speed; }
set
{
if (value < 0) speed = 0;
else speed = value;
}
}
12. Création implicite de "nombres magiques" ou de chaînes magiques
Si tu vois dans le code 42, "John", "SomeFile.txt" et d'autres valeurs "magiques" directement dans les méthodes — c'est potentiellement une erreur. Utilise plutôt des constantes ou des champs.
Exemple
public class ConfigManager
{
public void Save()
{
File.WriteAllText("config.txt", "some data"); // Chaîne magique !
}
}
Mieux :
public class ConfigManager
{
private const string ConfigFileName = "config.txt";
public void Save()
{
File.WriteAllText(ConfigFileName, "some data");
}
}
13. Erreur de copie : variables de référence sur le même objet
En C#, les variables-objets sont des références. Assigner une variable à une autre ne copie que la référence, pas l'objet lui-même. Ça cause souvent des changements "surprise".
Exemple
Student s1 = new Student("Vasya");
Student s2 = s1;
s1.Name = "Kolya";
Console.WriteLine(s2.Name); // Affichera "Kolya" !
Pourquoi ? Parce que s1 et s2 sont deux références sur le même objet !
14. Pas de feedback en cas d'erreur
C'est pas top quand une classe permet d'assigner des valeurs invalides. Par exemple, un âge négatif.
Exemple
public class Human
{
public int Age { get; set; }
}
var h = new Human();
h.Age = -50; // Aucun souci...
La logique de la classe doit protéger contre les valeurs absurdes :
private int age;
public int Age
{
get { return age; }
set
{
if (value < 0)
throw new ArgumentException("L'âge ne peut pas être négatif.");
age = value;
}
}
15. Confusion de portée (scope)
Parfois, des variables sont déclarées avec le même nom dans des scopes différents — dans une méthode et comme champ de classe.
Exemple
public class MyClass
{
int value = 10;
public void Foo()
{
int value = 99;
Console.WriteLine(value); // Affichera 99, pas 10 !
}
}
Pour accéder clairement au champ de la classe, utilise this.value.
16. Redéfinition de méthodes sans le mot-clé override
Quand tu veux redéfinir une méthode virtuelle de la classe de base, n'oublie pas le override !
Exemple
public class Animal
{
public virtual void Speak() => Console.WriteLine("L'animal parle");
}
public class Cat : Animal
{
public void Speak() => Console.WriteLine("Miaou !"); // Pas override !
}
Ici, la méthode de la classe de base n'est pas redéfinie : la nouvelle méthode masque juste l'ancienne (shadowing), ce qui peut causer des surprises avec les références de base.
La bonne façon :
public override void Speak() => Console.WriteLine("Miaou !");
17. Appel d'une méthode virtuelle depuis le constructeur
Ce n'est pas vraiment une erreur de compilation, mais ça cause souvent des bugs galères à trouver. Quand le constructeur de la classe de base appelle une méthode virtuelle, et que cette méthode est redéfinie dans l'enfant — au moment de l'appel, les champs de l'enfant peuvent ne pas être initialisés.
Exemple
public class Animal
{
public Animal()
{
Speak();
}
public virtual void Speak()
{
Console.WriteLine("Animal...");
}
}
public class Cat : Animal
{
public string Name { get; set; } = "Kitty";
public override void Speak()
{
Console.WriteLine($"Miaou ! Je suis {Name}");
}
}
Cat cat = new Cat();
// Au moment de l'appel à Speak(), le constructeur de Cat n'a PAS encore tourné, Name est encore null !
18. Décrire un objet uniquement via le constructeur (sans propriétés)
Si une classe n'a qu'un constructeur, et qu'après création l'objet ne peut plus être modifié — c'est bien pour les objets immuables, mais pas toujours pratique. Dans la plupart des cas, il vaut mieux laisser la possibilité de modifier les propriétés (ou au moins certaines).
19. Ignorer les conventions de nommage (naming conventions)
Les noms de classes commencent par une majuscule, les méthodes aussi, les champs par une minuscule et un underscore (ou en camelCase), les constantes — TOUT EN MAJUSCULES. Utiliser un style unique rend le code plus lisible et réduit le risque d'erreurs bêtes !
20. Champs et méthodes inutilisés
Si tu déclares un champ mais que tu ne l'utilises jamais — c'est du "code mort". L'IDE peut te le signaler. Moins il y a de "zones mortes", plus c'est simple de maintenir l'appli !
GO TO FULL VERSION