CodeGym /Courses /C# SELF /required properties an...

required properties and field properties

C# SELF
Level 17 , Lesson 3
Available

1. Introduction

You can code in C# without properties, but it's kinda like rollerblading through the White House — possible, but super awkward. Not only are we used to short syntax without extra getters and setters, but when your app starts working with "serious" models (like a User class describing a user in the system), it becomes important to make sure all the needed data is actually there.

For example, if you have a class like this:

public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}

It's super easy to forget to initialize the properties:

User user = new User(); // Name will be null, Age = 0

As a result, somewhere ten screens and a hundred logic twists later, you'll get the infamous NullReferenceException and spend ages hunting for the culprit.

Remember init-only properties?

Yeah, we can use initialization only at creation:

public string Name { get; init; }

But even with this syntax, nobody forces the class user to pass a value if they don't want to — most default constructors just initialize fields with default values (null, 0, etc.).

So how do you make sure the programmer (even yourself) doesn't forget to set the needed value? That's exactly why the required modifier was invented in C# 11.

2. required properties: strict initialization

The required modifier tells the compiler to make sure a specific property of an object is explicitly set when it's created. In plain English: if such a property isn't initialized when creating the object, the compiler won't let you through, and your IDE will draw a scary red squiggle.


public class User
{
    public required string Name { get; set; }
    public int Age { get; set; }
}
Required property with required

Let's try to create a user:

// Compile error: property Name is required to be initialized!
User user1 = new User();

Or like this:


// Compile error: required property Name not specified
User user2 = new User { Age = 18 };

And here's the correct way:

User user3 = new User { Name = "Hermione", Age = 18 };

How does required work?

The required modifier tells the compiler: "After any constructor of the object finishes, this property must be explicitly set."

This works for both regular properties and init-only ones:

public required string Name { get; init; }

If you define a custom constructor that initializes the required property's value, that's fine too.

Typical check scenarios

Scenario Compiler happy?
Required property not set
Set in object initializer ✔️
Set in constructor ✔️

Example in our "Dog" model

public class Dog
{
    public required string Name { get; set; }
    public int Age { get; set; }
}

Dog dog = new Dog { Name = "Rex", Age = 5 }; // All good!
Dog badDog = new Dog { Age = 2 }; // Error! Name not specified

Where does required really help?

  • Passing DTOs between layers: If you have an API, you need all required fields to always be present on input.
  • Complex models with required attributes: For example, Product with a required SKU, Order with a required number.
  • At interviews and code reviews: If you show off this syntax, your code will probably get some respect (and a bit of envy).

3. How does required work with constructors?

Sometimes you write a constructor yourself. What happens if you don't initialize a required property in the constructor or object initializer? The compiler will throw an error.


public class Article
{
    public required string Title { get; set; }
    public required string Author { get; set; }

    public Article()
    {
        // If you don't initialize Title and Author — compile error!
        // You can do this:
        Title = "Untitled";
        Author = "Unknown";
    }
}

If the constructor itself assigns values to required properties — all good. If not, you have to initialize these fields via the object initializer (new Article { ... }).

Usage specifics

  • required only works with properties, not fields.
  • required is not inherited — if a base property is required, but you don't specify required in the child, the compiler won't complain (but it's good practice to explicitly repeat required in the child).
  • required can't be applied to auto fields or anything except properties.

4. Arrow property syntax

With new C# versions, devs are all about concise and expressive code. One of the coolest property features is arrow syntax (or expression-bodied properties).

Sometimes you want to define a property that just returns a value with no extra logic. Before, you had to write a full getter with curly braces:

public int Age
{
    get { return birthYear > 0 ? DateTime.Now.Year - birthYear : 0; }
}

Now you can write it way shorter — using the arrow (=>):


public int Age => birthYear > 0 ? DateTime.Now.Year - birthYear : 0;

This syntax is called an expression-bodied property. It's perfect for simple calculations and makes your code more compact.

Example using get and set

public class Book
{
    private string _title;

    public string Title
    {
        get => _title;
        set => _title = value.Trim();
    }
}

Here, get returns the field value, and set assigns it after trimming extra spaces.

Example using only get (read-only):

If a property is read-only — you can write it without curly braces at all, just with =>.

public class Person
{
    private string name = "Mark Twain";

    // Read-only: computed property
    public string Name => name.ToUpper();
}

Here, the Name property is read-only — it always returns name in uppercase.

5. The field keyword for properties

Before C# 14, if you wanted to access the hidden field of an auto-property right inside the setter or getter (like to avoid recursion or add your own logic) — you couldn't. You had to declare the field explicitly.

C# 14 lets you access the hidden field of an auto-property using the field keyword:


public class Person
{
    public string Name
    {
        get => field; // field is the hidden field for Name
        set
        {
            if (string.IsNullOrWhiteSpace(value))
                throw new ArgumentException("Name can't be empty!");
            field = value; // use field instead of explicit _name
        }
    }
}

Before, you'd have to do this:

private string _name;
public string Name
{
    get => _name;
    set
    {
        if (string.IsNullOrWhiteSpace(value))
            throw new ArgumentException("Name can't be empty!");
        _name = value;
    }
}

One less variable declaration. The more compact the code, the better.

Why does it matter to access the field inside a property?

  • Sometimes you need to control where and how the value is stored (like if you want to return a copy, cache a result, or do lazy-loading).
  • If you want to use attributes or reflection — you might need the field by name.
  • In some (de)serialization or performance-tuning cases, you want more control over value storage.

Usage examples:

Data validation in setter

public double Grade
{
    get => field;
    set
    {
        if (value < 0 || value > 5)
            throw new ArgumentOutOfRangeException("Grade must be from 0 to 5");
        field = value;
    }
}

Value change statistics

public int StepCount
{
    get => field;
    set
    {
        if (value > field)
        {
            Console.WriteLine($"Yay! You did {value - field} more steps!");
        }
        field = value;
    }
}

Lazy Load

public string Data
{
    get
    {
        if (field == null)
            field = LoadDataFromDatabase();
        return field;
    }
    set => field = value;
}

6. Typical mistakes and gotchas

Mistake #1: forgot to initialize a required property.
The compiler won't let you get away with this and will throw an error at build time, helping you avoid runtime headaches.

Mistake #2: required properties don't work without full initialization in the constructor.
If the constructor doesn't take values for all required properties, the compiler will remind you that you missed something.

Mistake #3: trying to use required with const or readonly.
These modifiers are incompatible — required can only be used with regular properties. Trying to combine them will cause an error.

2
Task
C# SELF, level 17, lesson 3
Locked
Creating a class with required properties
Creating a class with required properties
2
Task
C# SELF, level 17, lesson 3
Locked
Custom logic in getters and setters using field
Custom logic in getters and setters using field
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION