-3

I am talking about the situation where there is no possible path leading to a specific variable being null at the point of the warning being thrown. Similar questions have been asked a lot before, especially here i found one highlighting this problem to an extend where even the C# program manager responded:

Why does this code give a "Possible null reference return" compiler warning?

However, i did not understand the explanation given. Or rather, they did talk about the lack of sophistication, and that the tracker only tracks a variables internal value, not the program flow around it. I want to provide an example of frustration i encounter consistently in C# that causes no issues in e.g. Java at all:

public double DoSomething(MyClass obj)
{
  if (obj is null) throw new ArgumentException("Object is null!");
  
  var result = OtherMethodCall(obj.A);
  // or alternative example:
  var result = obj.A * 10 / 3;
  
  return result;
}

Here, both C# and Java compilers have no issues - no warnings are thrown about A being possibly accessed from a null object because they see that a null check is done immediately before. However, if i extract/refactor the validation code into a separate method, C# loses the ability to see it:

public double DoSomething(MyClass obj)
{
  Validate(obj);
  
  var result = OtherMethodCall(obj.A); // C# throws warning that A is possibly accessed from a null object

  return result;
}

private void Validate(MyClass obj)
{
  if (obj is null) throw new ArgumentException("Object is null!");
}

The Java compiler can still see the path before the variable (obviously, for java code we would have to add "throws" declarations to the method signatures) and C# seems to not see the path anymore. If i have 2 or more methods in this class which require the same validation code, which is not sophisticated enough to warrant a separate validator class added as a dependency, it "forces" me to repeat myself to not have any warnings in my code or add quite a lot of ugly preprocessor or other statements to suppress the warnings. Can anyone explain to me why this is a problem in C# still? In the link above, they said it is intended but they plan to fix some of these situations in c# 9.0, but i am using 10.0.

Furious Gamer
  • 359
  • 1
  • 3
  • 16
  • 6
    Cross-method flow analysis is too complicated with too much room for error, but the compiler does offer [various attributes](https://learn.microsoft.com/dotnet/csharp/language-reference/attributes/nullable-analysis) to help the analysis along. In this case `[DoesNotReturnIf]` would help you out. – Jeroen Mostert Oct 26 '22 at 14:44
  • 5
    It would also help if you've provide realistic examples that didn't use keywords as identifiers. It shows you've never tried to compile the code you've presented. – Jon Skeet Oct 26 '22 at 14:59
  • You can submit suggestions here: https://developercommunity.visualstudio.com/ – Tu deschizi eu inchid Oct 26 '22 at 15:06
  • @JonSkeet That is correct, i was trying to use a simplified example so i dont have to type out the rest. But i should have paid attention to this. – Furious Gamer Oct 26 '22 at 16:17
  • @JeroenMostert Thank you! This is useful information. I am surprised as to why this question is being downvoted so much. Stackoverflow has really become a... difficult place. I have not participated in years but recently thought i should try to get input on here more often, but perhaps that is not a good idea. – Furious Gamer Oct 26 '22 at 16:20
  • @FuriousGamer I would suggest that you [edit] your question to rephrase the "why" question into a more answerable, and less opinion-based form, such as something along the lines of "how can I remove this nullable warning". – Sweeper Oct 26 '22 at 16:28
  • "Why does/doesn't language X do Y" questions tend to be poorly received because they can be read as rants, and also rarely allow objective answers (since very few people make executive decisions on what goes into C# and also roam SO). This question can also be read in a more constructive way, but people only have so much time to spend and the threshold for a downvote is low. As a general rule, avoiding any mention of "why" for language semantics in favor of "how" and "what" is a solid strategy. – Jeroen Mostert Oct 26 '22 at 18:43

1 Answers1

1

For the "why" question, it isn't quite answerable. The world only has limited time and resources, and people have unlimited ideas of what to put in a language. There's gotta be some things that are not implemented (yet).

In today's C#, you can extract the validation and exception-throwing code into methods like this:

using System.Diagnostics.CodeAnalysis;

double DoSomething(object? obj)
{
  if (!ValidateObject(obj)) ThrowCustomException(obj);
  
  // this shows that obj.ToString produces no warning 
  var result = Convert.ToDouble(obj.ToString());

  return result;
}

bool ValidateObject([NotNullWhen(true)] object? obj) => 
    // assuming you are doing a lot more validation in the real code
    obj is not null; 

[DoesNotReturn]
void ThrowCustomException(object? obj) =>
    // assuming that you are throwing a more "custom" exception in the real code
    // possibly making use of obj
    throw new NullReferenceException("obj is null!");

Note that the validation and the exception-throwing needs to go in separate methods, because there is no static analysis attribute that says "this method does not return if this parameter is null", so that you can apply to your version of ValidateObject which also throws exceptions. There is only [DoesNotReturn], which is unconditional, and [DoesNotReturnIf], which is conditional on a bool parameter.

One can tell the static analyser that a parameter is not null when the method returns true using [NotNullWhen]. And that's how you'd arrive at the above solution.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • This is useful information and shows concrete examples of workarounds, thank you. I am still kind of surprised about the fact that this seems to be treated so much with a sense of neglect by the community, since at least to me this is quite an important problem - if you have to rewrite your code in a way that was perfectly fine to not get "factually incorrect" warnings. But SO is quite a harsh place, and a question was already marked as an opinion, which is odd. Either way, i appreciate your response! I will try to get used to attributes and code analysis workarounds. – Furious Gamer Oct 26 '22 at 16:26