I have this code where the compiler says that myObj in ValidateMyObj(myObj) may be null.
Since it has to be not-null for string.IsNullOrEmpty to return false and enter the condition, how can it consider it could be null?
But most of all, how can it then consider that it cannot be null in myObj.Exists?
var myObj = myObjCol.FirstOrDefault(x => x.Member);
if (!string.IsNullOrEmpty(myObj?.StrProp))
{
ValidateMyObj(myObj);
if (ViewBag.IsValid)
myObj.Exists = true;
}
Edit: Playing with explicit null-check
Simply adding the explicit null-check gives the same behaviour:
var myObj = myObjCol.FirstOrDefault(x => x.Member);
if (myObj != null && !string.IsNullOrEmpty(myObj?.StrProp))
{
ValidateMyObj(myObj);
if (ViewBag.IsValid)
myObj.Exists = true;
}
this compiles to (according to the ILSpy decompiler when deactivating the decompilation of the ? operator)
MyObjType myObj = myObjCol.FirstOrDefault(x => x.Member);
if (myObj != null && !string.IsNullOrEmpty((myObj != null) ? myObj.StrProp : null))
{
ValidateMyObj(myObj);
if (ViewBag.IsValid)
myObj.Exists = true;
}
On the other hand, if I then remove the null-conditional operator, then the squiggly line disapears.
var myObj = myObjCol.FirstOrDefault(x => x.Member);
if (myObj != null && !string.IsNullOrEmpty(myObj.StrProp))
{
ValidateMyObj(myObj);
if (ViewBag.IsValid)
myObj.Exists = true;
}
In fact, it also disapears if I remove the explicit check and the null-conditional operator nor does it give one on the argument passed to ÌsNullOrEmpty`:
var myObj = myObjCol.FirstOrDefault(x => x.Member);
if (!string.IsNullOrEmpty(myObj.StrProp))
{
ValidateMyObj(myObj);
if (ViewBag.IsValid)
myObj.Exists = true;
}
If I got this right then i think it is because the IsNullOrEmpty is refering to the StrProp but the warning targets the myObj
Clarification:
if myObj is null then there isn't a StrProp to check for
The null-state analysis of the C# compiler tries to keep track of the null-state of every variable based on the context where it is used.
The null-state might be:
The value is known to be null.
The value is known to be not null.
The null-state is unknown (maybe-null).
After the assignment var myObj = myObjCol.FirstOrDefault(x => x.Member); myObj is in the maybe-null state (this actually depends on the framework – see below).
The call to string.IsNullOrEmpty doesn't change the null-state. The string.IsNullOrEmpty method is just an ordinary method. Without extra knowledge the compiler doesn't know anything about the null-state of the parameter.
It turns out that in .NET 6 the compiler gets this extra help. In .NET 6 the signature of that method is:
public static bool IsNullOrEmpty([NotNullWhen(false)] string? value);
In .NET Framework however the signature is:
public static bool IsNullOrEmpty(string value);
The NotNullWhen attribute tells the compiler that the argument passed to string.IsNullOrEmpty is not null when the method returns false. Therefore in .NET 6 you don't get any warnings in your original code because the compiler changes the null-state to not-null inside the if-block. In .NET Framework 4.8 (or earlier) it can't do that so the null-state inside the if-block is the same as outside.
Surprisingly after adding the explicit null check for myObj the squiggly line doesn't go away.
if (myObj != null && !string.IsNullOrEmpty(myObj?.StrProp)) { ... }
is equivalent to
if (myObj != null)
{
// null-state of myObj is not-null
if (!string.IsNullOrEmpty(myObj != null ? myObj.StrProp : null))
{
// the second test changed the null-state of myObj to maybe-null
}
}
When you now remove that second test the null-state doesn't change and the warning goes away.
The framework also influences how the return value of the FirstOrDefault method is treated.
Right at the beginning you have:
var myObj = myObjCol.FirstOrDefault(x => x.Member);`
Obviously this should set myObj to the maybe-null state and should give a warning when you then dereference the variable without checking for null:
if (!string.IsNullOrEmpty(myObj.StrProp)) { ... } // should warn: Dereference of a pssibly null reference
It seems that it doesn't do that when you are on .NET Framework. But it does when you are on .NET 6.
This can be explained when you look at the history of C# and .NET.
C# 8 was the first version to support nullable reference types. It was released shortly after the last version of .NET Framework (4.8).
In .NET Framework the signature is:
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
In .NET 6 it is:
public static TSource? FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
This means that the nullability context is unclear when you call FirstOrDefault<T> on .NET Framework but it is clear on .NET 6.
As far as I am aware the C# compiler team has decided not to warn when the context is unclear because that would give too many false warnings and would annoy too many people.
Having said that: If you want more reliable nullability analysis you should use a version of the framework which is fully null-aware.
Related
I have a complex object I want to check is valid. I have a method to check it, but C# nullability checks don't know about them:
#nullable enable
...
bool IsValid(Thing? thing)
{
return thing?.foo != null && thing?.bar != null;
}
...
if(IsValid(thing))
{
thing.foo.subProperty; // CS8602 warning: foo is possibly null here
Is there any way to apply something like TypeScript's type-gates here? If IsValid is true then we know that thing.foo is not null, but the C# analyser can't see inside the function. If I inline the check it can, but then I'm copy-pasting code and this is a simple example.
Is there any annotation or pattern where I can have the nullability analysis with the more complex checks?
You can use the null-forgiving operator like this:
if (IsValid(thing))
{
thing.foo!.subProperty;
}
As #JeroenMostert points out, while it won't help you with foo, an alternative is the NotNullWhen attribute.
The compiler knows thing is not null here, but foo might still be null.
bool IsValid([NotNullWhen(true)] Thing? thing)
{
return thing?.foo != null && thing?.bar != null;
}
if (IsValid(thing))
{
thing.foo;
}
I am trying to optimize the code using SonarQube
List<string> itemList = serviceObject.GetItems();
I tried to validate the list with the below code
if(itemList != null && itemList.Any()
{
//Some operations
}
when above code executed I am getting Sonarqube error remove this expression which always evaluates to "true"
So I refactor the code as
if(itemList == null || !itemList.Any())
return;
//Some Operations
when above code executed I am getting Sonarqube error remove this expression which always evaluates to "false"
Could anyone let me know what is wrong here?
You can shorten this to
if (itemList?.Count >0)
{
...
}
or
if (itemList?.Any() ==true)
{
...
}
?. is one of the Null conditional operators (the other is ?[]), the Elvis operator for short, that allows you to access potentially null variables without throwing. The result of the entire expression after the Elvis operator is nullable and returns null if the variable is null.
This means that itemList?.Count returns an Nullable<int>, and itemList?.Any() a Nullable<bool>. Nullable<T> defines relational operators between itself and its base type T but can't be used as T without an explicit cast. That's why (itemList?.Any() ==true) is needed.
If you use Nullable Reference Types though, itemList can't be null, so a simple comparison would be enough:
if (itemList.Count >0)
{
...
}
If you enable Nullable Reference Types by setting #nullable enable in a source file or <Nullable>enable</Nullable> in the csproj file, the compiler ensures that all variables, fields and methods that return reference types are not null, forcing you to either fix the problem or explicitly specify that a variable is nullable.
With NRTs enabled this line :
List<string> itemList = serviceObject.GetItems();
Would only compile without warnings if GetItems never returned a null. If the compiler doubts this, it would issue a warning advising you to either fix the problem or explicitly declare itemList as nullable with :
List<string>? itemList = serviceObject.GetItems();
I believe it is due to null Comparision.
itemList != null
There is a high chance that serviceObject.GetItems(); is guaranteed to not return null by having a [NotNull] Annotation. Hence the null check is redundant.
How can I show that a method will never return null (Design by contract) in C#
if( itemList !=null ) {//Do something...}
List<string> itemList = new List<string>();
itemList = serviceObject.GetItems();
if(itemList!=null && itemList.Count() > 0 )
{
//Some operations
}
Count is enough to validate a list
List will always not be null but will have no elements. but you have to instatiate it so it wont throw an exception.
With C# 6.0 in the VS2015 preview we have a new operator, ?., which can be used like this:
public class A {
string PropertyOfA { get; set; }
}
...
var a = new A();
var foo = "bar";
if(a?.PropertyOfA != foo) {
//somecode
}
What exactly does it do?
It's the null conditional operator. It basically means:
"Evaluate the first operand; if that's null, stop, with a result of null. Otherwise, evaluate the second operand (as a member access of the first operand)."
In your example, the point is that if a is null, then a?.PropertyOfA will evaluate to null rather than throwing an exception - it will then compare that null reference with foo (using string's == overload), find they're not equal and execution will go into the body of the if statement.
In other words, it's like this:
string bar = (a == null ? null : a.PropertyOfA);
if (bar != foo)
{
...
}
... except that a is only evaluated once.
Note that this can change the type of the expression, too. For example, consider FileInfo.Length. That's a property of type long, but if you use it with the null conditional operator, you end up with an expression of type long?:
FileInfo fi = ...; // fi could be null
long? length = fi?.Length; // If fi is null, length will be null
It can be very useful when flattening a hierarchy and/or mapping objects. Instead of:
if (Model.Model2 == null
|| Model.Model2.Model3 == null
|| Model.Model2.Model3.Model4 == null
|| Model.Model2.Model3.Model4.Name == null)
{
mapped.Name = "N/A"
}
else
{
mapped.Name = Model.Model2.Model3.Model4.Name;
}
It can be written like (same logic as above)
mapped.Name = Model.Model2?.Model3?.Model4?.Name ?? "N/A";
DotNetFiddle.Net Working Example.
(the ?? or null-coalescing operator is different than the ? or null conditional operator).
It can also be used out side of assignment operators with Action. Instead of
Action<TValue> myAction = null;
if (myAction != null)
{
myAction(TValue);
}
It can be simplified to:
myAction?.Invoke(TValue);
DotNetFiddle Example:
using System;
public class Program
{
public static void Main()
{
Action<string> consoleWrite = null;
consoleWrite?.Invoke("Test 1");
consoleWrite = (s) => Console.WriteLine(s);
consoleWrite?.Invoke("Test 2");
}
}
Result:
Test 2
Basically, I have applied ?. operator after Model as well. I am trying to know that whether it can be applied directly to the model or does it only work with the navigation properties?
The ? or null conditional operator operators on the left value, regardless of the type of value. And the compiler doesn't care what the value is on the right. It's simple compiler magic (meaning it does something you can already do, just in a simplified why).
For example
var a = model?.Value;
is the same as saying
var a = model == null ? null : model.Value;
In the second case the evaluation of checking for null has no associate with the value returned. The null conditional operator basically just always return null if the left value is null.
The type of member (Method, Field, Property, Constructor) .Value is irrelevant.
The reason your DotNetFiddle example doesn't work is because the compiler being use for the .Net 4.7.2 isn't compatible with the c# version that support the null conditional operator. Changing it to .Net 5, works:
https://dotnetfiddle.net/7EWoO5
This is relatively new to C# which makes it easy for us to call the functions with respect to the null or non-null values in method chaining.
old way to achieve the same thing was:
var functionCaller = this.member;
if (functionCaller!= null)
functionCaller.someFunction(var someParam);
and now it has been made much easier with just:
member?.someFunction(var someParam);
I strongly recommend this doc page.
I have recently added code contracts to a very large project. After working my way through a few hundred warnings adding assertions to pacify the checker I am left with some warnings which appear to be obviously incorrect! This probably the most simple example I can make (full code is here, if you think the details may be important):
protected Thing DoStuff(A a)
{
Contract.Requires(a != null);
//CodeContracts: Consider adding the postcondition Contract.Ensures(Contract.Result<Thing>() == null); to provide extra-documentation to the library clients
D outResult;
var result = DoSomething(a, out outResult);
if (result == null)
return null;
return new Thing(outResult, result);
}
This suggestion is quite clearly wrong (I have unit tests which return non-null values from this function to prove it)! The only way it could be true is if "DoSomething" also always returns null, but it is not making any suggestion regarding that.
Edit: I have fixed the above problem by totally rewriting the DoSomething method to not use an out result (instead it returns tuple containing both outResult and result). However I still have other false warnings which I would like to solve and probably have the same root cause.
So really this is two questions:
Am I doing something wrong or missing something obvious here?
Assuming CC is simply wrong is there anything I can do to mitigate this kind of problem in the future - at the very least hide the warning!
Re : Contract.Ensures on the return value
In both your MVCE and production code, following the 'burden of proof' upstream, the issue will almost certainly be with the called SelectScript extension method (or DoSomething in the MVCE), where the static analyzer has inferred (possibly incorrectly) that the extension method always returns null, and hence that in the calling method SelectSingle that the first branch (also returning null) would always be chosen, hence the recommended postcondition for null.
I can't find your code for SelectScript, but on VS 2013 update 4 / CC 1.7.11202.10, I can only repeat the Contracts warning by explicitly returning only null from SelectScript and enabling the "Infer ensures" static checking option, OR by explicitly adding a Contract.Ensures(Contract.Result<ScriptReference>() == null); to SelectScript, e.g. with ensures inference on:
public static ScriptReference SelectScript(
this IEnumerable<KeyValuePair<float, KeyValuePair<string, string>[]>> tags,
Func<double> random,
Func<KeyValuePair<string, string>[], Type[], ScriptReference> finder,
out KeyValuePair<string, string>[] selectedTags,
Type t)
{
selectedTags = null;
return null;
}
Produces the same warning in the calling method SelectSingle:
CodeContracts: Consider adding the postcondition Contract.Ensures(Contract.Result() == null); to provide extra-documentation to the library clients
However, for me, the analyzer does appear to correctly infer that the below code has branches which both return null, and non-null, and doesn't recommend the precondition in the caller:
public static ScriptReference SelectScript(
this IEnumerable<KeyValuePair<float, KeyValuePair<string, string>[]>> tags,
Func<double> random,
Func<KeyValuePair<string, string>[], Type[], ScriptReference> finder,
out KeyValuePair<string, string>[] selectedTags,
Type t)
{
Contract.Requires(random != null);
selectedTags = null;
return (random() > 0.5)
? null
: new ScriptReference();
}
Re : Contract.Ensures on the out value
Out of interest, it is also possible to add contracts to out parameters, by using Contract.ValueAtReturn -
reference, section 2.2.3 p8.
e.g. If you are still receiving the warning on the out parameter, you could use grek40's idea to suppress the warnings in the caller by adding this to SelectScript:
Contract.Ensures(Contract.ValueAtReturn(out selectedTags) == null ||
Contract.ValueAtReturn(out selectedTags) != null);
With C# 6.0 in the VS2015 preview we have a new operator, ?., which can be used like this:
public class A {
string PropertyOfA { get; set; }
}
...
var a = new A();
var foo = "bar";
if(a?.PropertyOfA != foo) {
//somecode
}
What exactly does it do?
It's the null conditional operator. It basically means:
"Evaluate the first operand; if that's null, stop, with a result of null. Otherwise, evaluate the second operand (as a member access of the first operand)."
In your example, the point is that if a is null, then a?.PropertyOfA will evaluate to null rather than throwing an exception - it will then compare that null reference with foo (using string's == overload), find they're not equal and execution will go into the body of the if statement.
In other words, it's like this:
string bar = (a == null ? null : a.PropertyOfA);
if (bar != foo)
{
...
}
... except that a is only evaluated once.
Note that this can change the type of the expression, too. For example, consider FileInfo.Length. That's a property of type long, but if you use it with the null conditional operator, you end up with an expression of type long?:
FileInfo fi = ...; // fi could be null
long? length = fi?.Length; // If fi is null, length will be null
It can be very useful when flattening a hierarchy and/or mapping objects. Instead of:
if (Model.Model2 == null
|| Model.Model2.Model3 == null
|| Model.Model2.Model3.Model4 == null
|| Model.Model2.Model3.Model4.Name == null)
{
mapped.Name = "N/A"
}
else
{
mapped.Name = Model.Model2.Model3.Model4.Name;
}
It can be written like (same logic as above)
mapped.Name = Model.Model2?.Model3?.Model4?.Name ?? "N/A";
DotNetFiddle.Net Working Example.
(the ?? or null-coalescing operator is different than the ? or null conditional operator).
It can also be used out side of assignment operators with Action. Instead of
Action<TValue> myAction = null;
if (myAction != null)
{
myAction(TValue);
}
It can be simplified to:
myAction?.Invoke(TValue);
DotNetFiddle Example:
using System;
public class Program
{
public static void Main()
{
Action<string> consoleWrite = null;
consoleWrite?.Invoke("Test 1");
consoleWrite = (s) => Console.WriteLine(s);
consoleWrite?.Invoke("Test 2");
}
}
Result:
Test 2
Basically, I have applied ?. operator after Model as well. I am trying to know that whether it can be applied directly to the model or does it only work with the navigation properties?
The ? or null conditional operator operators on the left value, regardless of the type of value. And the compiler doesn't care what the value is on the right. It's simple compiler magic (meaning it does something you can already do, just in a simplified why).
For example
var a = model?.Value;
is the same as saying
var a = model == null ? null : model.Value;
In the second case the evaluation of checking for null has no associate with the value returned. The null conditional operator basically just always return null if the left value is null.
The type of member (Method, Field, Property, Constructor) .Value is irrelevant.
The reason your DotNetFiddle example doesn't work is because the compiler being use for the .Net 4.7.2 isn't compatible with the c# version that support the null conditional operator. Changing it to .Net 5, works:
https://dotnetfiddle.net/7EWoO5
This is relatively new to C# which makes it easy for us to call the functions with respect to the null or non-null values in method chaining.
old way to achieve the same thing was:
var functionCaller = this.member;
if (functionCaller!= null)
functionCaller.someFunction(var someParam);
and now it has been made much easier with just:
member?.someFunction(var someParam);
I strongly recommend this doc page.