# Required Keyword

C# 11 introduces a new keyword: `required`. This [keyword](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required) can be applied onto fields or properties to make them required to be set during initialization. In this post I will focus on using *required properties*.

In the past developers could create `init` properties that could be set only at initialization time by the type's constructor or object initializer. However, the compiler did not require the developer to explicitly set a value to a property.

Required properties make object initializers issue a compiler error when the developer does not set a *required property*.

In this post I will explore the following topics for required properties:

- Required Property Example
- Order of Initialization Precedence
- Nullability
- Use-Cases and Limitations
- Constructors and Derived Types
- Serialization
- IL Under the Hood

## Required Property Example

A regular init (non-required) property could look like the following in C#:

```csharp
public class Dto
{
  public string Value { get; init; }
}
```

The required counterpart of this property adds the `required` keyword to the declaration of the property:

```csharp
public class Dto
{
  public required string Value { get; init; }
}
```

This will instruct the compiler to issue a warning if the developer would not set the property. For example, the following case omits setting the *Value* property:

```csharp
Console.WriteLine(new Dto().Value);
```

The code above returns a compile error: `Error	CS9035	Required member 'Dto.Value' must be set in the object initializer or attribute constructor.`. This compile error is also shown when the developer of `Dto` type provides a constructor to set the `Value` property inside the constructor. However, I will revisit setting *required properties* in constructors later in this post.

## Order of Initialization Precedence

One may ponder about the question: what the order of precedence is when setting a value for required properties in constructor and object initializer as well. The following example answers the question:

```csharp
Console.WriteLine(new Derived() { Value = "4" }.Value);

public class Dto
{
  public Dto()
  {
    Console.WriteLine(Value);
    Value = "2";
    Console.WriteLine(Value);
  }

  public required string Value { get; init; } = "1";
}

public class Derived : Dto
{
  public Derived()
  {
    Value = "3";
    Console.WriteLine(Value);
  }
}

```

The code snippet above prints the numbers in order: 1, 2, 3, 4 to the console. A type or a derived type may set a value in its constructor, but that will be overwritten by the value set in the object initializer.

> Notice, that the property is `init`, which means we cannot change its value outside the initialization phase, but it changes its value 4 times during it. This could have negative performance implications in certain cases.

## Nullability

Required properties do not enforce to have a non-null value set for the property. For reference types a developer can still set `null`, which satisfies the compiler. If the field is non-nullable reference type, the default behavior of the compiler is to issue a warning. To escalate nullability warnings to errors increase the severity of [nullability warnings](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/nullable-warnings) to errors by setting

```xml
<WarningsAsErrors>Nullable</WarningsAsErrors>
```

in the project's csproj file.

## Use-Cases and Limitations

Typical use-cases for required types could be types that may prefer not to use constructors but still require properties to be set during initialization phase. DTO classes and entities could be good candidates. However, using *required properties* become increasingly useful along with `init` properties and non-nullable reference types, when nullability warnings are treated as errors.

I would particularly find useful to have types with *required properties* for `IOption<T>` from *Microsoft.Extensions.Options* namespace. However, `IOption<T>` has `new()` generic parameter constraint which is not supported by types with *required properties*.

## Constructors and Derived Types

A type's constructor may be attributed with `[SetsRequiredMembers]`. This turns off required properties check when using this given constructor (and derived type's constructors using this constructor). However, such a constructor might be evil and omit setting some *required properties*. Another concern to notice: currently there is no way to tell that only *some* of the *required properties* would be set by a constructor attributed with `[SetsRequiredMembers]`.

As noted above, when a constructor is not attributed with `[SetsRequiredMembers]`, setting a value for a *required property* in the constructor will not satisfy the compiler, the developer will be still required to set a value when the object is initialized.

## Serialization

As *required properties* is a new feature, not all serializers consider the required quality of a property. **System.Text.Json** serializer is aware of *required properties*. We can safely serialize and deserialize objects as:

```csharp
var serialized = JsonSerializer.Serialize(new Dto() { Value = "3" });
Console.WriteLine(serialized);
var data = JsonSerializer.Deserialize<Dto>(serialized);
Console.WriteLine(data.Value);
```

For example, the above code snippet will correctly serialize and deserialize the object while printing the following text to the console:

```
{"Value":"3"}
3
```

When a message to be deserialized does not have a required property, an exception is thrown:

```csharp
JsonSerializer.Deserialize<Dto>("""{"OtherValue":"3"}""");
```

The above code snippet results a `JsonException`: *JSON deserialization for type 'Dto' was missing required properties, including the following: Value* at runtime.

Using the **Newtonsoft.Json** serializer, no exception will be thrown, and the value of the property will be the default value, or any value set in a corresponding constructor of the object:

```csharp
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<Dto>("""{"OtherValue":"3"}""");

// Prints out the default value of the Value property.
Console.WriteLine(data.Value);
```

## IL Under the Hood

How does *required properties* feature work? Is it a C# compiler feature or is it backed up by the CLR? So far, the observations suggest that it is a C# compiler feature:

- `[SetsRequiredMembers]` attribute turns off validation completely at compile time
- different serializers behave differently when there is no value passed for a required field

Decompiling the generated IL for `Dto` type results the following C#:

```csharp
[RequiredMember]
public class Dto
{
    [RequiredMember]
    public string Value { get; init; }

    [Obsolete("Constructors of types with required members are not supported in this version of your compiler.", true)]
    [CompilerFeatureRequired("RequiredMembers")]
    public Dto() { }
}
```

A few interesting points compared to type without required properties:

- Both the type and the property are attributed with `[RequiredMember]`
- The default constructor is attributed with `[Obsolete]` which generated a compiler error when being used: this may tell existing tooling (that may be unaware of the *required properties* feature), that this constructor may not be used the regular way. This also prevents older compilers using these constructors incorrectly.
- The default constructor is also attributed with `[CompilerFeatureRequired("RequiredMembers")]` which tells the compiler that this constructor must be used with the *RequiredMembers* feature during type initialization.

Can required properties make the code execute faster? In general, as this is a compiler feature, it should not. However, when comparing it with a type `DtoRegular`, which sets a `string.Empty` for the *Value* property to avoid the nullability warning/error, we may get surprising results.

```csharp
public class DtoRegular
{
    public string Value { get; init; } = string.Empty;
}
```

Executing the following benchmarks, the results show that `Dto` with the required property executes faster:

```csharp
    [Benchmark]
    public Dto Required() => new Dto() { Value = "3" };

    [Benchmark]
    public DtoRegular NotRequired() => new DtoRegular() { Value = "3" };
```

```
|      Method |     Mean |     Error |    StdDev |
|------------ |---------:|----------:|----------:|
|    Required | 3.461 ns | 0.0389 ns | 0.0364 ns |
| NotRequired | 4.442 ns | 0.1162 ns | 0.1030 ns |
```

Further investigation shows that a sizable portion of this difference is caused by having to set the `string.Empty` value for `DtoRegular` in its constructor, then the property needs to be set again by the object initializer.

When the `string.Empty` default property value is omitted for `DtoRegular`, the optimized (tier-1) JIT compilation results the same generated assembly code for both `Dto` and `DtoRegular` types.