Introduction: Why Did the Question About Auto-Properties Gather Thousands of Views?
\n\nIf you've ever written in C#, you've likely encountered a simple but important question: "How to correctly set an initial value for an auto-property?". This question on Stack Overflow has gathered tens of thousands of views, and for good reason. The apparent simplicity hides many pitfalls.
\n\nImagine: you create a User class, and you want the Name property to default to an empty string, not null. What could go wrong, you might think? But in practice, developers make typical C# property initialization mistakes that lead to NullReferenceException or non-obvious behavior.
In this article, we'll break down the TOP-5 mistakes and show you how to avoid them. You'll learn modern approaches—from C# 6 to C# 12—and understand which method to choose for your project.
\n\n\n\n
Mistake #1: Ignoring Auto-Property Initialization
\n\nThe most common mistake is not setting an initial value for reference types. Many beginners write:
\n\npublic class User\n{\n public string Name { get; set; } // null by default\n public List<string> Roles { get; set; } // null\n}\n\nIn C#, auto-properties for reference types default to null. This leads to NullReferenceException issues when you forget to assign a value before use.
How to Fix?
\nAlways explicitly set a C# auto-property initializer. The simplest way is to use C# 6 syntax:
\n\npublic class User\n{\n public string Name { get; set; } = string.Empty;\n public List<string> Roles { get; set; } = new List<string>();\n}\n\n\n\n\nTip: Use
\nstring.Emptyinstead of empty quotes—this improves readability and follows C# best practices.
\n\n
Mistake #2: Initialization in the Constructor Without Considering the Call Chain
\n\nAnother common mistake is setting the C# default value only in the constructor, while ignoring property initializers. This can lead to confusion, especially with inheritance.
\n\npublic class BaseClass\n{\n public int Value { get; set; }\n\n public BaseClass()\n {\n Value = 10;\n }\n}\n\npublic class DerivedClass : BaseClass\n{\n public DerivedClass()\n {\n // Value is already = 10, but we can overwrite it\n }\n}\n\nThe problem: if you add an initializer to the Value property and keep the assignment in the constructor, the execution order may surprise you. Initializers run before the base class constructor body, but after the derived class constructor call.
How to Avoid?
\nChoose one method: either an initializer or a constructor. It's better to prefer C# auto-property initializers, as they are more predictable and concise.
\n\npublic class BaseClass\n{\n public int Value { get; set; } = 10; // Single source of truth\n}\n\n\n\n
Mistake #3: Using Readonly Fields Instead of Auto-Properties
\n\nSome developers, trying to set an initial value, abandon auto-properties and use public fields:
\n\npublic class Config\n{\n public readonly int MaxRetries = 3; // Mistake: encapsulation violation\n}\n\nThis is bad practice. Fields violate encapsulation—you won't be able to add logic to the getter/setter without changing the API. Additionally, this creates problems with serialization or when used in WPF/Blazor.
\n\nThe Correct Approach
\nUse auto-properties with initialization or C# 9 init-only properties:<