Consider this code (C# 12/.NET 8):
class Content
{
public string Value { get; set; }
}
class Something
{
public bool IsOK { get; set; }
public Content? TheContent { get; set; }
}
Something ProcessIt()
{
var result = new Something();
if (/*whatever*/)
{
result.IsOK = true;
result.TheContent = new Content() { Value = "Hello!" };
}
else result.IsOK = false;
return result;
}
string? DoWork()
{
var something = ProcessIt();
if (!something.IsOK)
return null;
return something.TheContent.Value; // Null ref warning CS8602
}
Is there any way that I can annotate the code anywhere to avoid CS8602 after if (!something.IsOK)?
I know that I can use something.TheContent! on each reference, but if I have many references, that's not very neat.
I can also do Content content = something.TheContent! and then use content for the remainder of DoWork. Maybe that's the way to go, but if there's way to tell the null checking system that "from now on (until it's modified) assume that something.TheContent is not null", I'd like to know...
TheContenthas a value and anything can modifyIsOK. Why not ignoreIsOKand usesomething.TheContent?.Value? Or returnContent?directly and use pattern matching to handle theNullcase? There are ways to create aResult<Something>orOption<Something>class, if that's what you want, but it won't be easier or safer to use thanContent?with nullability andWarnings As ErrorsIsOKand change the property toIsOK=>TheContent!=nullbut that's not really better than null checking. You could useif (something.TheContent is x{ return x.Value;}instead, to both null-check and extract the data.(Content? content, bool IsOk)with exhaustive pattern matching ieswitch (result) { case (Content x,true): ,case(_,false)...}. The compiler ensures all cases are handled. Another option is to have anIResult<T>withGood<T>andBad<T>implementations. All these options ensure nulls can't even be representedContent content = something.TheContent!combined with a comment motivating the!.