2

I searched for an answer for it and couldn't find a clear answer. And yes, I know that similar questions exist everywhere. I hope I can get an answer here.

Let's assume I have a Person class with 2 properties (FirstName, MiddleName). FirstName is required & MiddleName is optional.

I want the FirstName property to always have non-nullable data.

Here are some options I think of (but none of them seems to be perfect).

One optional way would be to use the short syntax of records:

// FirstName might be null (bad)
// MiddleName is optional (good)
public record Person(string FirstName, string? MiddleName);

Another way would be to use the null-forgiving operator, but still the same problem.

// FirstName might be null (bad)
// MiddleName is optional (good)
public record Person
{
    public string FirstName { get; init; } = null!;

    public string? MiddleName { get; init; }
}

The old option would be to check the input in the constructor:

// FirstName is required and will always have some data (good)
// MiddleName is optional (good)
// Long syntax (bad)
public record Person
{
    public string FirstName { get; init; }

    public string? MiddleName { get; init; }

    public Person(string firstName, string? middleName)
    {
        // Probably it would be better to check if it is NullOrWhiteSpace.
        ArgumentNullException.ThrowIfNull(firstName);

        FirstName = firstName;
        MiddleName = middleName;
    }
}

If the last option is the way to enforce a non-null value, then I would ask:

  1. With all the new shortened syntax, is it really the way we should do it?
  2. When should I use the shortened way of writing records? (I would always want to validate that required fields have values and do it in the constructor).
Misha Zaslavsky
  • 8,414
  • 11
  • 70
  • 116
  • "*but still the same problem*" -- I don't think you ever said what the problem actually *is*? Similarly: "*MiddleName is optional (good)*" -- why is this good? – canton7 Dec 21 '21 at 14:55
  • @canton7 The problem is that I want to make "FirstName" required and not null and force it. If null is possible then it is bad. And "MiddleName" is good because it is optional and this is what I want. – Misha Zaslavsky Dec 21 '21 at 14:58
  • 6
    Records are not supposed to be your go-to solution for all situations. They come with a very clear and limited feature set. If you can't live with all those features, either accept that you have to write more code than the "basic syntax" or just don't use records to begin with. If you **must have** values in those properties, your **only** option is a constructor with guard clauses. – Lasse V. Karlsen Dec 21 '21 at 14:58
  • 1
    There's currently no way to mix validation and primary ctors, [e.g. see here](https://github.com/dotnet/csharplang/discussions/5320). Which means you're basically stuck with an explicit ctor. – canton7 Dec 21 '21 at 14:59
  • Here's a [proposal](https://github.com/dotnet/csharplang/blob/main/proposals/required-members.md) that is interesting regarding the context of this question – NotFound Dec 21 '21 at 15:01
  • @LasseV.Karlsen So, if I understand you correctly, it means I should still use the last approach I specified with the constructor? – Misha Zaslavsky Dec 21 '21 at 15:01
  • @404 That's amazing. Actually, I thought it will be part of C# 10 but unfortunately, not yet. Ok, probably should wait for this one. Thanks. – Misha Zaslavsky Dec 21 '21 at 15:02
  • 1
    Yes, at the moment you have no other option than the explicit constructor with the if-statements or the `?? throw ...` syntax. – Lasse V. Karlsen Dec 21 '21 at 15:15
  • 1
    [Related](https://stackoverflow.com/questions/64784374/c-sharp-9-records-validation). – Guru Stron Dec 21 '21 at 17:14

3 Answers3

5

In C# 11.0 preview it is possible to use required in the property declaration.

public record Person
{
    public required string FirstName { get; init; }

    public string? MiddleName { get; init; }
}

A good explanation article about it can be found here.

Misha Zaslavsky
  • 8,414
  • 11
  • 70
  • 116
  • 1
    This answer is completely wrong. C# 11 is not officially supported on .NET 6 and Required Members doesn't work on .NET 6 at all. – KUTlime Jan 10 '23 at 07:13
  • You can actually use some features of C# 11, such as required properties in .NET 6 and previous runtime version. Details here: https://blog.genezini.com/p/how-to-use-c-sharp-11-features-in-dotnet-6-or-older-versions/ – Daniel Genezini Feb 07 '23 at 16:13
  • Check out [PolySharp](https://github.com/Sergio0694/PolySharp) – Dan Friedman Jul 26 '23 at 14:53
0

i would probably go for the classic way of just enforcing it on the constructor. don't really see the downsides of that when FirstName is always required

-1

The best possible solution with minimum overengineering is an old simple constructor, so your code in the question is the best possible solution. Why?

Neither nullable reference types, nor a record, nor required guarantees that a property will not be a null.


Nullabe reference types is a static analysis tool. It doesn't ensure anything in runtime. It is just information for a developer that null should be handled properly.


The required members in C# 11 does not work on .NET 6. It is by design, see the GitHub issue here.

There are missing attributes RequiredMemberAttribute and CompilerFeatureRequiredAttribute in .NET 6, see the framework reference.

Builds completely fine on .NET 7.

In addition, required keyword just enforce passing a value to the property, but it doesn't say anything what the value should or should not be. You can pass null there easily. You will get a warning if you have nullable reference types turn on, but that is it.

The marked ✅ answer is completely wrong here.


A record doesn't give you anything here and it is not a good use case for a record when you have to write non-trivial logic to a constructor.

KUTlime
  • 5,889
  • 1
  • 18
  • 29
  • 1
    Maybe, but this doesn't answer the question "What is the best way to make properties required"? This should be said in a comment to the answer it refers to. Answers on Stack Overflow should always be a serious attempt at answering the question, unlike many forum sites. – Gert Arnold Jan 08 '23 at 16:40