Note, this goes off the assumption that Category
is a class, which seeing you tagged this "nullable reference types", that's a pretty good assumption.
Whether you include = default!
or not has no effect on the final compiled code.
public class C {
public string A { get; set; }
public string B { get; set; } = default!;
}
A
and B
will be treated the same way by the compiler.
public class C
{
[CompilerGenerated]
private string <A>k__BackingField;
[CompilerGenerated]
private string <B>k__BackingField;
public string A
{
[CompilerGenerated]
get { return <A>k__BackingField; }
[CompilerGenerated]
set { <A>k__BackingField = value; }
}
public string B
{
[CompilerGenerated]
get { return <B>k__BackingField; }
[CompilerGenerated]
set { <B>k__BackingField = value; }
}
}
And this makes sense. default
of a class is null
, so = default
just makes the property (and backing field) null, which is what would have been done anyways had you not typed = default
.
So why the !
? It's to make the compiler not throw a warning.
No really, that's it. It's to suppress the compiler warning you would have got had it not been there. When you use nullable reference types, the compiler wants you to always assign a value to your properties before the constructor exits. Using !
calms the compiler down as you pinky-promise that it won't be null when you try to read it back, but satisfies the requirement that some value is assigned.
public string A { get; set; }
// "A" might have a null value after the constructor exits
public string A { get; set; } = default;
// "Uh dude, you're trying to assign null to something that doesn't accept nulls".
public string A { get; set; } = default!;
// "Ok, you're assigning null, but I'm going to trust you know what you're doing".
You can also get around the problem by specifying a value in the constructor
public class C {
public string A { get; set; } // no warning
public C()
{
A = "f";
}
}
Another thing to note, C# 11 just came out (November 2022), which has the required
keyword, which takes care of all this nonsense.
public class C
{
public required string A { get; set; }
// no warning, no default, no constructor needed
}