0

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...

4
  • 1
    Probably, using annotations, but a redesign is probably a better option. There's no guarantee that TheContent has a value and anything can modify IsOK. Why not ignore IsOK and use something.TheContent?.Value ? Or return Content? directly and use pattern matching to handle the Null case? There are ways to create a Result<Something> or Option<Something> class, if that's what you want, but it won't be easier or safer to use than Content? with nullability and Warnings As Errors Commented Oct 2 at 9:51
  • 1
    You could use eg MemberNotNullWhen on IsOK and change the property to IsOK=>TheContent!=null but that's not really better than null checking. You could use if (something.TheContent is x{ return x.Value;} instead, to both null-check and extract the data. Commented Oct 2 at 10:02
  • 1
    Another option, return (Content? content, bool IsOk) with exhaustive pattern matching ie switch (result) { case (Content x,true): ,case(_,false)...}. The compiler ensures all cases are handled. Another option is to have an IResult<T> with Good<T> and Bad<T> implementations. All these options ensure nulls can't even be represented Commented Oct 2 at 10:03
  • Some ideas, thanks! In my code there are multiple states, not just OK/not OK, and it's currently beyond my man hour budget to refactor that, so I'll keep these suggestions in mind for future efforts. For now, I'll settle for Content content = something.TheContent! combined with a comment motivating the !. Commented Oct 3 at 8:51

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.