C# Required Keyword: Syntax and Usage
c# required keyword: Learn how the C# required keyword enforces mandatory property initialization, its compile-time behavior, and practical patterns for constructors.
The c# required keyword, introduced with C# 11 and .NET 7, marks a field or property as mandatory for object initialization. When you apply required to a member, the compiler requires that member to be set during object creation, either through an object initializer or a constructor marked with the SetsRequiredMembers attribute. This shifts certain validation from runtime to compile time, catching missing data before the application starts.
Declaring Required Members
To declare a required member, add the required modifier to a field or property declaration. The member must be accessible from the initialization context, and it cannot be static or abstract. Here is a minimal example:
public class Product { public required string Name { get; set; } public required decimal Price { get; set; } }
When you create a Product, the compiler enforces that both Name and Price are set:
var product = new Product { Name = "Laptop", Price = 999.99m };
If you omit one of the required members, the code will not compile. The compiler emits an error indicating the missing member. This behavior is particularly useful for data transfer objects, configuration models, and other types where incomplete data should be rejected as early as possible.
Constructor Interaction with Required Members
Types with required members add a subtlety to constructor design. A plain constructor that does not set all required members will not compile unless it uses the SetsRequiredMembers attribute. For example:
public class Product { public required string Name { get; set; } public required decimal Price { get; set; } public Product(string name, decimal price) { Name = name; Price = price; } }
This constructor is valid because it assigns both required members. If it only assigned Name, compilation would fail because Price remains unset.
When a constructor does not initialize every required member, the compiler demands that callers use an object initializer to fill the gaps. That means a constructor like this:
public Product(string name) { Name = name; }
Forces the caller to write:
var product = new Product("Laptop") { Price = 999.99m };
If you want to silence this requirement entirely, you can use the SetsRequiredMembers attribute on the constructor:
public class Product { public required string Name { get; set; } public required decimal Price { get; set; } [SetsRequiredMembers] public Product() { } }
This attribute tells the compiler that the constructor takes responsibility for initializing all required members. It is up to the developer to ensure that the constructor actually does so; the compiler does not verify the body. Misusing it by leaving a required member unset results in runtime NullReferenceException or uninitialized value when the member is accessed later.
Validation at Compile Time vs. Runtime
The primary advantage of the required keyword is moving mandatory-field validation from runtime to compile time. Without it, you might write a runtime check in a constructor or method:
public Product(string name) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Name is required.", nameof(name)); Name = name; }
This check runs every time an object is created, and missing data may only surface as an exception. With required, the compiler rejects the code if a member is not initialized. This is more efficient because no runtime validation code is executed, and it is more predictable because the error appears at build time.
However, required only guarantees that a value is assigned. It does not validate the value's content. For example, a string property marked required could still be set to an empty string. For semantic validation, you still need runtime checks in constructors or property setters.
Interplay with Inheritance and Interfaces
Required members behave differently across inheritance hierarchies. If a base class has a required member, derived classes must also initialize it. Consider:
public abstract class Vehicle { public required string Model { get; set; } } public class Car : Vehicle { public required int Doors { get; set; } }
When constructing a Car, the compiler requires both Model and Doors to be set:
var car = new Car { Model = "Sedan", Doors = 4 };
You cannot mark an overridden property as required if the base class does not. Conversely, if the base class declares a property as required, the derived class must keep that requirement; you cannot remove it. This behavior ensures that any code that expects a base type can rely on the required member being initialized.
Interfaces pose a limitation: you cannot mark an interface property as required. The required modifier is only allowed on class and struct members. If an interface defines a property, implementations in classes can mark it required, but callers using the interface type cannot be forced to initialize it through the interface reference. For example:
public interface IProduct { string Name { get; set; } } public class Product : IProduct { public required string Name { get; set; } }
If you instantiate a Product directly, the compiler enforces the requirement. But if you use IProduct as the variable type, the compiler cannot know at compile time that Name is required, so object initializer syntax still works, but the requirement is not enforced.
This limitation matters when you design APIs that accept interfaces or return them. If you want to guarantee initialization through an abstraction, you need to consider factory methods or other patterns that enforce the contract.
When Required Members Are a Good Fit
The required keyword is most beneficial for types that are primarily used with object initializers. Examples include configuration option classes, data transfer objects, request models, and view models. These types often have many properties, and forgetting one can lead to subtle bugs. Marking them required converts an occasional runtime error into a compile-time error.
However, for domain entities that have rich behavior and invalidation logic, constructors remain the better choice. A constructor can enforce invariants and ensure that the object is fully valid after creation. Instead of relying on required, you can have a constructor that takes all necessary parameters:
public class Product { public string Name { get; } public decimal Price { get; } public Product(string name, decimal price) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Name cannot be empty.", nameof(name)); if (price < 0) throw new ArgumentOutOfRangeException(nameof(price), "Price cannot be negative."); Name = name; Price = price; } }
This approach ensures that every Product instance is fully initialized and valid. With required, you could have a property setter with validation, but it would be more verbose and harder to maintain across many properties.
Use required when you value the convenience of object initializers and compile-time enforcement, but accept that some validation may still need runtime checks.
Refactoring Implications and Maintainability
Adding required to an existing property is a breaking change for all code that creates instances of that type. Every object initializer that omits the member will fail to compile. This is intentional but can be disruptive in large codebases. Before marking a member required, consider who uses the type and whether all those call sites can be updated.
Removing required from a member is non-breaking; existing code that sets the member will still compile. This asymmetry means you can gradually tighten initialization requirements without breaking existing code, but loosening them later would require coordination.
Another maintainability concern is the SetsRequiredMembers attribute. If you use it on a constructor to bypass the compiler check, you lose the compile-time safety net. Ensure that the constructor truly initializes every required member. A common mistake is to add SetsRequiredMembers to a parameterless constructor and then forget to initialize a required member. The result is a compile-time pass but a runtime NullReferenceException when you access the missing member.
A better approach is to avoid SetsRequiredMembers altogether and rely on the compiler to enforce initialization. If you need a parameterless constructor for serialization or other framework requirements, you might be better off not marking members as required and instead validating in that constructor or a custom setter.
Runtime Cost and Performance Considerations
At runtime, the required keyword has negligible cost. It does not emit any additional IL instructions for validation; it simply influences compile-time analysis. Compared to manual null checks in constructors, using required can even reduce runtime overhead because the compiler generates no validation code. However, this benefit is often small in practice because null checks are cheap.
The main performance consideration is not the keyword itself but the initialization pattern. Object initializer syntax assigns properties after the constructor runs. If your type has a constructor that performs complex logic, that logic executes before the required members are set. This is the same with any object initializer. There is no special performance penalty associated with required.
When you use SetsRequiredMembers, the compiler skips adding implicit checks, so the constructor may be slightly faster. But relying on this attribute can introduce runtime null-reference bugs, so micro-optimizations like this are rarely worth the risk.
Limitations Across C# Versions and Tooling
The required keyword is a C# 11 feature and requires .NET SDK 7 or later. If you are targeting an earlier runtime, such as .NET Framework or .NET Core 3.1, the compiler might not support this syntax. Even if you use a newer SDK, you may still target older frameworks, but the C# language version must be set to 11 explicitly if your project uses an older default. In .NET 7 and later projects, C# 11 is the default, so no extra configuration is needed.
Another limitation is that required cannot be applied to fields that are readonly unless you use a constructor with SetsRequiredMembers. That is because readonly fields must be assigned in the constructor, not through object initializers. For example, this is illegal:
public class Product { public required readonly string Name; // Error }
To have a required readonly field, you must initialize it in a constructor and apply SetsRequiredMembers to that constructor. Alternatively, you can use a getter-only auto-property and initialize it through a constructor. This constraint means required works best with read-write members.
Also, required is not supported on records in the same way as on classes. Records already provide a primary constructor that requires all parameters, so you typically do not need required. You can use it on record properties, but it may conflict with positional parameters. In practice, records that enforce initialization via constructor parameters are clearer and should be preferred.
Finally, be aware that required does not work with anonymous types or dynamic. Anonymous types are implicitly named and cannot have the required modifier. Dynamic binding bypasses compile-time checks entirely, so required members are not enforced.
Understanding these boundaries helps you decide when required is the right tool and when another pattern gives you the same guarantees with less friction.