1. Name Clash Problem: Field, Property, Parameter
Newbies often run into situations where property names, constructor parameters, and private fields have the same name. The compiler won't complain, but the result might not be what you expect.
Example
public class Student
{
private string name;
public Student(string name)
{
name = name; // "Seems legit..."
}
public void PrintName()
{
Console.WriteLine(name);
}
}
So what happens? The PrintName() method has nothing to print: the private field name will stay null! That's because inside the constructor, name = name; works with the local parameter, not the class field.
How to avoid it
Use the this keyword to refer to class fields/properties:
public Student(string name)
{
this.name = name; // Now it's all good!
}
Note: Rider and other IDEs will help you spot these mistakes — don't ignore their hints!
2. Missing Default Constructor: When Do You Need It?
If you declare at least one custom constructor, the compiler won't create an "empty" default constructor for you anymore. This often leads to errors, especially when you try to create an object without parameters.
Example
public class Book
{
public string Title { get; set; }
// Explicitly declared constructor
public Book(string title)
{
Title = title;
}
}
var book = new Book(); // Compiler: "Beep-beep! No parameterless constructor!"
If you want to create an instance both with and without parameters, don't forget to explicitly add the needed constructor:
public Book() { }
public Book(string title)
{
Title = title;
}
3. Access Modifiers: The Private Life of Public People
A common rookie mistake is not thinking about access modifiers. By default, class fields and methods have the private modifier, and struct members are also private. Forgetting or not specifying can make it impossible to use the needed properties or methods outside the class.
Example
public class Animal
{
string name; // private by default
public void PrintName()
{
Console.WriteLine(name);
}
}
var animal = new Animal();
animal.name = "Fluffy"; // Compilation error!
The compiler won't let you access a private member. It's better to explicitly specify the modifier:
public string Name;
or
private string name;
For smarter access, use properties:
public string Name { get; set; }
4. Forgot to Initialize a Field: The null Trap
A super common trap — a class field isn't initialized. This is especially important if the field will be used in methods called before explicit initialization.
Example
public class Cat
{
public string Name;
public void SayHello()
{
Console.WriteLine($"Meow! Name length is {Name.Length} letters!"); // Possible NullReferenceException
}
}
var cat = new Cat();
cat.SayHello(); // What a tragedy!
The variable Name is null, and trying to access Length will throw a NullReferenceException. Always keep an eye on object state after creation!
Tip: Use constructors to require important fields, and mark properties as required (in new C# - with required).
5. Infinite Recursion in Auto-Properties: Copy-Paste Fail
Sometimes you write a property by hand and mess up — for example, inside the getter or setter you refer to the property itself (not the private field), which leads to an endless loop.
Example
public class Dog
{
public int Age
{
get { return Age; } // Oops!
set { Age = value; } // Double oops!
}
}
This code, whenever you call Age, will call itself... forever (until the stack blows up — recursive self-eating).
The Right Way
Use a separate private field:
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
Or just use an auto-property:
public int Age { get; set; }
6. Inconsistent Naming
Being careful with case and names is super important in programming. C# is Case-Sensitive, so Name, name, NAME are three different identifiers.
Also, if you change a field or property name, make sure you change it everywhere! Rider can help refactor, but typos can still sneak in (especially if you have similar names).
7. Using the Wrong Modifier (static/instance)
Sometimes beginners mix up instance methods and static methods. The problem pops up when you try to access a field/method in a way that's not allowed by C# syntax.
Example
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); // Error!
The Multiply method isn't static, so you can't call it by class name without creating an object:
var helper = new MathHelper();
var mul = helper.Multiply(2, 3); // Now it's right
8. Mistakes When Inheriting Constructors
If your class inherits from another class, don't forget that the base class might require parameters in its constructor.
Example
public class Animal
{
public string Name;
public Animal(string name)
{
Name = name;
}
}
public class Dog : Animal
{
public Dog() { } // Error: base class requires name!
}
The compiler won't let you declare such a constructor. You need to explicitly call the base class constructor:
public class Dog : Animal
{
public Dog(string name) : base(name) { }
}
9. Forgot to Implement All Interface Members
If your class implements an interface but doesn't implement all its methods — you'll get a compile error: "Class does not fully implement the interface".
Example
public interface IWalker
{
void Walk();
void Run();
}
public class Turtle : IWalker
{
public void Walk()
{
Console.WriteLine("Slow and steady...");
}
// Oops! Forgot about Run!
}
The IDE will complain, and Turtle won't compile until you implement all interface methods.
10. Using Uninitialized Objects
In C#, objects are created explicitly with new. If you just declare a reference variable but don't assign it an object — it's null. If you try to access fields/methods, you'll get the famous NullReferenceException.
Example
Student student;
student.PrintName(); // Surprise!
You must initialize the object:
Student student = new Student("Alice");
student.PrintName();
11. Mistake: public Fields Instead of Properties
Old "anti-pattern": declaring all class fields as public. Why is this bad? Fields aren't protected, there's no control over changes, encapsulation is broken!
Example
public class Car
{
public int speed; // Don't do this!
}
It's better to use properties:
public class Car
{
public int Speed { get; set; }
}
Properties let you add checks, logic, restrictions:
private int speed;
public int Speed
{
get { return speed; }
set
{
if (value < 0) speed = 0;
else speed = value;
}
}
12. Implicitly Creating "Magic Numbers" or Strings
If you see 42, "Ivan", "SomeFile.txt" and other "magic" values right in method bodies — that's a potential mistake. It's better to use constants or fields.
Example
public class ConfigManager
{
public void Save()
{
File.WriteAllText("config.txt", "some data"); // Magic string!
}
}
Better:
public class ConfigManager
{
private const string ConfigFileName = "config.txt";
public void Save()
{
File.WriteAllText(ConfigFileName, "some data");
}
}
13. Copy Mistake: Reference Variables Pointing to the Same Object
In C#, object variables are references. Assigning one variable to another just copies the reference, not the object itself. This often leads to "sudden" changes.
Example
Student s1 = new Student("John");
Student s2 = s1;
s1.Name = "Bob";
Console.WriteLine(s2.Name); // Will print "Bob"!
Why? Because s1 and s2 are two references to the same object!
14. No Feedback on Errors
It's bad when a class lets you assign invalid values. For example, a negative age.
Example
public class Human
{
public int Age { get; set; }
}
var h = new Human();
h.Age = -50; // No problem...
The class logic should protect against nonsense values:
private int age;
public int Age
{
get { return age; }
set
{
if (value < 0)
throw new ArgumentException("Age can't be negative.");
age = value;
}
}
15. Scope Confusion
Sometimes variables are declared with the same names in different scopes — inside a method and as class fields.
Example
public class MyClass
{
int value = 10;
public void Foo()
{
int value = 99;
Console.WriteLine(value); // Will print 99, not 10!
}
}
To clearly refer to the class field, use this.value.
16. Overriding Methods Without the override Keyword
When you want to override a virtual method from a base class, don't forget override!
Example
public class Animal
{
public virtual void Speak() => Console.WriteLine("Animal speaks");
}
public class Cat : Animal
{
public void Speak() => Console.WriteLine("Meow!"); // Not override!
}
Here, the base class method isn't overridden: the new method just hides the old one (shadowing), which can lead to surprises when working with base references.
The right way:
public override void Speak() => Console.WriteLine("Meow!");
17. Calling a Virtual Method from a Constructor
This isn't exactly a compile error, but it often leads to hard-to-find bugs. When a base class constructor calls a virtual method, and that method is overridden in a subclass — at the moment of the call, subclass fields might not be initialized yet.
Example
public class Animal
{
public Animal()
{
Speak();
}
public virtual void Speak()
{
Console.WriteLine("Animal...");
}
}
public class Cat : Animal
{
public string Name { get; set; } = "Fluffy";
public override void Speak()
{
Console.WriteLine($"Meow! I'm {Name}");
}
}
Cat cat = new Cat();
// At the moment Speak() is called, Cat's constructor hasn't run yet, Name is still null!
18. Describing an Object Only Through the Constructor (No Properties)
If a class only has a constructor, and after creation the object can't be changed — that's fine for immutable objects, but not always convenient. In most cases, it's better to let the class user change properties (or at least some of them).
19. Ignoring Standard Naming Conventions
Class names start with a capital letter, methods too, fields — with a lowercase and underscore (or camelCase), constants — ALL CAPS. Using a single style not only makes code more readable, but also lowers the risk of random mistakes!
20. Unused Fields and Methods
If you created a field but never use it — that's "dead code". The IDE can highlight these cases. The fewer "dead zones", the easier it is to maintain your app!
GO TO FULL VERSION