I have 2 pieces of code where the core logic is same but SonarQube behaves different and gives me a warning:
First see the no warning snip:
Now the warning thrown:
Why am I seeing the warning at one place and not other. ALso, How Can I overcome this warning.
I have already tried:
foreach (JObject item in jArray)
{
if(item != null)
{
clusterIds.Add(item.GetValue("value").ToString());
}}
or checking if item.values != null
In recent .NET versions, .ToString() is declared as string? ToString(), so it could return null.
The difference you're seeing is because the string concatenation operator += allows a null string to be concatenated to a non-null string (it does nothing), but your clusterIds is declared as a list that cannot contain nulls, so you get the warning that you're seeing.
To be clear, this is OK:
string x = "x";
x += null;
Console.WriteLine(x);
And this will give you a warning:
List<string> y = new List<string>();
y.Add(null); // Not OK
You can suppress the warning by adding a null-forgiving operator:
clusterIds.Add(item.GetValue("value").ToString()!);
Related
I have a method that returns a tuple (MyEnum, MyObject?). There is one and only one enum value that means MyObject is not null - all the others mean MyObject will be null (and the string will have a message).
Something along the lines of
(MyEnum response, Package? package) MyMethod()
{
if (Today == NiceDay)
{
return (MyEnum.Happy, new Package("I'm happy!"));
}
if (Today == RainyDay)
{
return (MyEnum.Pensive, null);
}
if (Today == SnowyDay)
{
return (MyEnum.Cold, null);
}
}
Obviously, if I try and use MyMethod().package.message, the compiler will warn me about the possibility of a null reference. I'm aware of the null-forgiving operator, but that kind of feels like a quick-fix.
Is there a way to "tell" the compiler to expect a value when MyMethod().response is MyEnum.Happy, and null when it is any other value, or is the null-forgiving operator the correct and expected way to deal with this situation?
Currently attributes for null-state static analysis interpreted by the C# compiler do not support neither specifying nullability of selected properties of returned value nor scenario when specific constant/enum value can be tied to nullability of parameters (except bool constants). The closest thing which can be done - return boolean value and tie out parameter to the return:
bool MyMethod(out MyEnum response, [NotNullWhen(true)] out Package? package)
{
string Today = "";
response = MyEnum.Happy;
package = new Package("");
return true;
}
Usage:
if(MyMethod(out _, out var packageValue))
{
Console.WriteLine(packageValue.ToString()); // no warning
}
So there are many ways to handle null/null warnings.
First
If you are 100% sure that the value cannot be null here you can use ! operator something like this package!.Message
Second
If You are not sure and there is only one condition in which the value can not be null its better to use the ternary operator like this var result = MyMethod().response == MyEnum.Happy ? MyMethod().package.message : string.Empty;
Third
you can use ?? operator like this var message = MyMethod().package?.message ?? "No message found"; or empty string according to your use case.
As a suggestion to resolve the issue, instead of the null have a static property in the Package class that defines an empty package:
class Package {
public static Package None => new Package { Message = "No package." };
}
In your code make the return for Package non-nullable and use
return (MyEnum.Pensive, Package.None);
Suppose I have a class with a lot of members and nested members and do this call and one of the variables is null (other than the last on each side of the equation):
Obj.Field.NextField.NextNextField = NextObj.OtherField.NextOtherField.NextNextOtherField;
I will get a NullReferenceException saying that an object is null in this line.
In this case, there are 6 different cases where the exception could originate from.
I had this situation quite often by now and always do the following to figure out which member actually is null.
public static void PrintNullOrigin(params object[] _args)
{
for (int i = 0; i < _args.Length; i++)
{
if (_args[i] == null)
{
print(_args[i] + " is null!");
}
}
}
But in this case, you still had to do it like this:
PrintNullOrigin(Obj, NextObj, Obj?.Field, NextObj?.OtherField, ...);
Is there a way that any time a NullReferenceException is thrown, a logger will do this automatically?
I tried getting the members in the line where the NullReferenceException originated from by the Exception object, but I can't find anything that makes it easy.
EDIT:
I have to highlight here, that I want to know if it is possible for this to be made outside the Visual Studios debugging mode.
In Unity the debugging mode of Visual Studio should be rarely used due to crashes that could occur and performance loss when running.
There is no way to print which one of fields is null when you access it. You still have to do some check before accessing the field.
This check can be in many ways:
You can some function like CheckForNull(NextObj, "NextObj.OtherField.NextOtherField.NextNextOtherField") and then by splitting the second parameter and using Reflection - you can investigate which of fields in this path is null
This way is a bit more complex: the second parameter can have type like Expression<Func<NextObj, T>> and value as obj => NextObj.OtherField.NextOtherField.NextNextOtherField. So you'll have expression of this mapping and you can find which of fields is null by examining this expression tree.
But overall if you have something like this: "NextObj.OtherField.NextOtherField.NextNextOtherField"
This is bad sign - because it is poorly architected application when you have to do this.
you can do something like this:
var propertiesTree = "NextObj.OtherField.NextOtherField.NextNextOtherField".Split('.');
object obj = NextObj;
for(var index = 1; index < propertiesTree.Length; index++)
{
var property = obj.GetType().GetProperty(propertiesTree[index]);
var value = property.GetValue(obj);
if (value == null) { throw new Exception($"{propertiesTree[index]} is null"); }
obj = value;
}
// if we are here - then all fields are not null
I've tried to reproduce a null-forgiving code applied to a value type, but it does not generate any warning: dotnetfiddle.net. In actual code, I'm getting a warning. I'm actually compiling with .NET Core 6.0.
I'm getting multiple compile-time warnings on a code base, some of them related to null-forgiving code. I'm trying to use either SomeNullableValue.Value or SomeNullableValue!, but the compiler complains I'm possibly passing null argument to a function in both ways.
The case I'm dealing with now is an enum that is initially null, but is assigned later in the same control flow; in this case, it is Ast.ContStmtTarget? t, where Ast.ContStmtTarget is an enum:
NextToken();
Ast.ContStmtTarget? t = null;
if (CurrentToken.Type == Token.Keyword) {
switch (CurrentToken.StringValue) {
case "do": t = Ast.ContStmtTarget.Do; break;
case "for": t = Ast.ContStmtTarget.For; break;
case "loop": t = Ast.ContStmtTarget.Loop; break;
case "while": t = Ast.ContStmtTarget.While; break;
}
}
if (!t.HasValue) {
FatalError(0x80A0400, GetTokenSpan());
}
r = new Ast.ContStmt(t.Value);
The compiler is outputting warning in the last line, r = ...;, with the column pointing to t.Value. Also, the Ast.ContStmt constructor takes a non-nullable value (the enum).
...\Parser.cs(1410,38): warning CS8629: Nullable value type may be null.
I've put compilable project on GitHub (dotnet build):
Parser
Ast.ContStmt
compiler is warning you that you can reach that line with t == null. Does FatalError return? I assume it throws but the compiler doesnt know that
do
if (!t.HasValue) {
FatalError(0x80A0400, GetTokenSpan());
} else{
r = new Ast.ContStmt(t.Value);
}
You can mark FatalError with DoesNotReturnAttribute to help compiler determine that code after if is unreachable in case !t.HasValue otherwise compiler can't verify that code will not actually be called:
[DoesNotReturn]
private void FatalError(int msgId, Span? span, Dictionary<string, object>? vars = null) {
throw new SyntaxException(Program.Collect(new Problem(msgId, false, vars, span.Value)));
}
I've a project on which I enabled the new Nullable reference type feature
<Nullable>enable</Nullable>
Now let's consider this code
public class Foo { }
var foo = new Foo();
The compiler considers the foo variable to be nullable (Foo?).
Why is that? I don't understand.
Now with the Nullable reference type feature enabled the returned Foo object isn't supposed to be null because it is a non-nullable type.
If I wanted it to be nullable I'd specify it has a Foo?
So why is the compiler saying it's a nullable variable?
Thank you
EDIT
Here is a screenshot of what I'm describing here. When you hover your mouse over the foo variable
In the original implementation, foo would have been inferred as a Foo.
However, people complained that this got in the way of things like:
string? GetThing() => ...
var result = "";
if (condition)
{
result = GetThing();
}
If result is inferred as a string, then the result = GetThing() line causes a warning: GetThing() returns a string?, and there's a warning if you try and assign a string? to a string.
The solution was to infer result as a string?, but the compiler knows that it's currently not null (its "flow state" is "NotNull").
This means that:
string? GetThing() => ...
var result = "";
// No warning, as the compiler knows that result isn't null
int l1 = result.Length;
if (condition)
{
result = GetThing();
}
// Warning: the compiler knows 'result' might have been re-assigned
int l2 = result.Length;
For other examples of the flow state at work, see things like:
string? result = GetString();
if (result == null)
throw new Exception();
// No warning: the compiler knows that result can't be null here: if it was,
// the exception above would have been thrown
int l1 = result.Length;
string? result = GetString();
// Warning: result might be null
int l1 = result.Length;
// No warning: the compiler knows that result can't be null here: if it was,
// the line above would have thrown
int l2 = result.Length;
string result = "hello";
if (result == null)
Console.WriteLine("NULL!");
// Warning: because we checked for null above, the compiler assumes that we
// know something that it doesn't, and so result might be null.
int l1 = result.Length;
Check out the specification on nullable reference types. It states that var infers an annotated type for reference types.
The part under the heading nullable implicitly typed local variables reads:
var infers an annotated type for reference types. For instance, in var s = ""; the var is inferred as string?.
I am playing with the nullable types in c# 8 and I found a problem that is bugging me.
Suppose I have a method which takes a nullable parameter. When a parameter is null, I want to throw a specific Exception. But I want the method to be clean and check the parameter somewhere else. The check method throws an exception, so after the method the parameter can not be null.
Unfortunately, the compiler does not see that and throws warnings at me.
Here's the method:
public void Foo(string? argument)
{
GuardAgainst.Null(argument, nameof(argument));
string variable = argument; // <-- Warning CS8600 Converting null literal or possible null value to non - nullable type
var length = argument.Length; //<--Warning CS8602 Dereference of a possibly null reference
}
Here's the check method:
public static void Null(string? text, string paramName)
{
if (text == null)
throw new ArgumentNullException(paramName);
}
Now, I can suppress the warning like this:
#pragma warning disable CS8602
var length = argument.Length;
#pragma warning restore CS8602
but it kind of kills my intention to keep my code clean.
So my question is: is there a nicer way to suppress the warnings? Or maybe tell a compiler that from now on the parameter is guaranteed to not be null?
This does what you want:
public static void Null<T>([NotNull] T? value, string paramName)
{
if (value == null)
throw new ArgumentNullException(paramName);
}
The [NotNull] attribute instructs the analysis that, after calling this method, value will not be null.
This means you don't need the ! operator, which is much cleaner and more natural.
void M(string? argument)
{
GuardAgainst.Null(argument, nameof(argument));
string variable = argument; // no warning
// ...
}
The use of an unconstrained generic type parameter T here means that this approach works for both reference types (such as string) and nullable value types (such as int?).
If you're using .NET 6, you can simplify this even further via CallerArgumentExpressionAttribute as follows:
public static void Null<T>(
[NotNull] T? value,
[CallerArgumentExpression(parameterName: "value")] string? paramName = null)
{
if (value == null)
throw new ArgumentNullException(paramName);
}
With that, the second argument can be omitted, and the caller can be simplified to:
GuardAgainst.Null(argument);
Think of the ? specifier on a type as meaning two things: 1) the value can be null before the call, and 2) the value can be null afterwards. Another way of writing it is [AllowNull, MaybeNull]. The absence of ? in a nullable context equally means [DisallowNull, NotNull]. In the case of your Null method, we end up with [AllowNull, NotNull] due to the manual specification of NotNull.
Ok, it looks like there is a really simple solution to it - the ! operator
You have to use it once after the guard, and then it considered to be not null:
public void Foo(string? argument)
{
GuardAgainst.Null(argument, nameof(argument));
var length = argument!.Length;
}
Consider this solution with the null-coalescing operator ??
The null-coalescing operator ?? returns the value of its left-hand
operand if it isn't null; otherwise, it evaluates the right-hand
operand and returns its result. The ?? operator doesn't evaluate its
right-hand operand if the left-hand operand evaluates to non-null.
public void Foo(string? argument)
{
string variable = argument ?? throw new ArgumentNullException(nameof(argument));
var length = argument.Length;
}
This solution is much cleaner in my opinion. You avoid inspecting GuardAgainst class and .Null() static method implemetation details.