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);
Related
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.
I am writing a function that checks if an output is DBNull and returns null if the generic type is nullable. If not it simply throws the error.
Update: added all recommendations
public T Get<T>(string key)
{
int ordinal = reader.GetOrdinal(key);
if (reader.IsDBNull(ordinal))
{
if (typeof(T).GetTypeInfo().IsValueType && Nullable.GetUnderlyingType(typeof(T)) == null) // isn't a nullable field
throw new InvalidCastException();
else return default(T);
}
return reader.GetFieldValue<T>(ordinal);
}
However I am not sure if default(T) returns null for every nullable field. If now is there any other way to make it return null?
Yes, default(T) is the right kind of null-like value for every T that is actually a SomeType? / Nullable<SomeType>, so what you have should work fine.
You might want to consider things like string and byte[] though - these can also come from databases and can be null.
You might also want to think about what the error should be if someone simply makes a mistake and asks for <int> when the value is a <decimal>. That would cause InvalidCastException. There is an IsDBNull() method on IDataReader that might be more appropriate than using the exception.
Finally: prefer throw; to throw e;
In terms of computer resources, catching and handling an exception is an extremely expensive task. Your method is using the exception as part of its logic flow. This is an incorrect way of looking at the problem you are wanting to solve,.
In addition, you are catching specifically InvalidCastException exceptions. This exception can occur in other cases other than attempting to cast a null reference. You are hiding/misrepresenting a potentially valid error; something that can cost you many hours of frustrating, hair-pulling debugging.
The following should give you the same behavior as the original method, but without the overhead of unwinding the stack during the integrated error handling.
public T Get<T>(string key)
{
if(reader.IsDbNull(reader.GetOrdinal(key)))
{
//IF YOU SPECIFICALLY WANT TO THROW AN ERROR IF A VALUE TYPE
//if (typeof(T).IsValueType)
//{ throw new InvalidCastException(); }
return default(T);
}
return reader.GetFieldValue<T>(reader.GetOrdinal(key));
}
I've got this code:
if (null == _priceComplianceSummaryList)
{
_priceComplianceSummaryList = new List<PriceComplianceSummary>();
}
Resharper flags it as an issue, suggesting, "Replace 'if' statement with respective branch" If I acquiesce, the code above changes to:
_priceComplianceSummaryList = new List<PriceComplianceSummary>();
Yet it seems R# is often more the belt-and-suspenders type of "cat," urging me to always check if something is null prior to referencing it. So is this ostensibly reckless behavior on its part really just a matter of efficiency? IOW, does "new List<>" only generate a new list if the istance variable (_priceComplianceSummaryList) is null, without having to explicitly check that?
"Replace 'if' statement with respective branch" R# suggestion means that there is no scenarios when your boolean expression returns false. For example,
void SomeMethod(bool firstParam)
{
var secondParam = true;
if (firstParam || secondParam)
{
Console.WriteLine();
}
}
This code will refactor by R# because firstParam || secondParam is always true.
Then, your 2 examples of code are not always equivalent, but in your scenario they are.
Say I have a class
class T
{
int num;
public T(int num)
{
this.num = num;
}
public void p()
{
Console.WriteLine(this.num);
}
}
And I have a null object T t = null. Calling the method t.p() will cause a NullReferenceException no matter what.
Is it not possible to test if the object is null (by using this == null (to check if the object is null within the method)), so is there a way to set a default method that will work on a null object?
In whatever code that calls t.p() you should check if t is null. You shouldn't be calling methods on a null instance.
Regarding the second part of your question, no it is not possible to set a default method that will be called if the instance of that object is null.
I should point out that there is also the Null Object Pattern, that, depending on the exact circumstances of usage may help. I would not use it as replacement for null checks though. I've found the pattern useful in some cases.
In C/C++ you can do this, but not (easily) in C#.
For example, you might want to have a check for "if a string is empty" or "if a collection is empty", and treat a null object as meaning "empty". For this sort of case, being able to call an IsEmpty() method via a null pointer/reference results in what seems like more elegant/readable code:
if (myList.IsEmpty())
...
rather than
if (myList == null || myList.IsEmpty())
...
However, it is also extremely dangerous as it hides unusual/unexpected behaviour, and encourages the caller to stop checking for nulls. As you cannot guarantee that every method you call will protect you from nulls, how do you know that it is safe to stop checking for nulls in the calling code? Or do you check for null twice (in both the calling and called code), just in case? If you are calling many methods on the same object instance, wouldn't it be far more efficient to check for null once at the start?
So although this pattern can be used in some languages, it is not considered a good practice.
This is (one reason) why, in C#, such code is not allowed. Instead the preferred pattern is to provide a static method to check the status:
if (string.IsNullOrEmpty(myString))
....
This is only slightly less readable, but much safer as the null check is clearly visible to the reader. Even without "IsNull" in the title, tou can see that the reference is being passed to another method, and it is more reasonable to assume that the called method will be well written and check for nulls. Being transparent and explicit makes code much easier for others to read.
C# also provides the null coalescing ?? operator to make the null checks cleaner in the calling code. If you want a default to use if the object is null, then you can use this form:
string result = myString ?? string.Empty;
...which in this case will return myString if it is non-null, or string.Empty if it is null, thus guaranteeing that result is never null.
Finally, in C# 6 you can use the ?. operator, which combines an "if not null" check with an access, so you can replace:
if (element != null && element.FirstChild != null)
element.FirstChild.DoSomething();
with
element?.FirstChild?.DoSomething();
This is functionally equivalent, but a much more compact syntax.
Calling an instance method on a null reference will always result in a NullReferenceException. You have to check if the reference is not null or use the C# 6 ?. operator to do it for you.
T t = null;
t?.p(); // no method is called
You can however use an extension method on a null reference. It has some limitations, as you can only access public members in an extension method, but might be useful (especially if you cannot use C# 6 and ?.):
class T
{
public int Number { get; private set; } // public property
public T(int number)
{
Number = number;
}
}
static class Extensions
{
public static void PrintT(this T t)
{
if (t == null) Console.WriteLine("null");
else Console.WriteLine(t.Number);
}
}
T t = null;
t.PrintT(); // no exception, writes "null" to the console
It is possible to call an instance method on a null reference in CIL, simply using call instead of callvirt. The latter checks the run-time type of the referenced object, that's why it throws NRE immediately. call should call the method normally, but with the implicit this parameter set to null, and throw on first access to any member of this.
Edit
The System.Reflection.Emit namespace in C# contains types that let you dynamically emit IL. You can use it to call an instance method with a call instead of callvirt. (I modified code posted in this answer to work for methods. The sample here will only work for parameterless methods)
public static void MakeNonVirtualCall<T>(T c, Expression<Action<T>> f)
{
var expression = f.Body as MethodCallExpression;
if (expression == null) throw new ArgumentException();
var dyn = new DynamicMethod("NVCall", null, new[] { typeof(T) }, typeof(T).Module, true);
var il = dyn.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, expression.Method);
il.Emit(OpCodes.Ret);
((Action<T>)dyn.CreateDelegate(typeof(Action<T>)))(c);
}
Now, assuming we have a class
class Class
{
public void Method()
{
if (this == null) Console.WriteLine("`this` is null");
else Console.WriteLine("`this` is not null");
}
}
We can use it as
Class nullRef = null;
Class instance = new Class();
MakeNonVirtualCall(nullRef, t => t.Method()); // no exception, prints "`this` is null"
MakeNonVirtualCall(instance, t => t.Method()); // prints "`this` is not null"
It works - an instance method in a C# class can be called on a null reference from IL (but still not directly from C#).
Note that the MSDN documentation is incorrect here:
Calls to an instance (or virtual) method must push that instance reference before any of the user-visible arguments. The instance reference must not be a null reference.
Just check for null in the calling code.
T t = null;
// somewhere further..
if (t == null)
//t is null, don't use it
else
//save to use t
Another way (if you don't expect the object to be null is to use try/catch):
T t = null;
// somewhere further..
try {
t.p();
}
catch(NullReferenceException ex) {
// t is null
}
No you can't. And I'll tell you why. The keyword this refers to whichever object is accessing a variable or calling a method. So a this inside doSomething() would refer to object in object.doSomething().
Now coming to your question about null, when you write T t = null; it means you made a variable of type T which REFERS to NOTHING!!! And by nothing I mean, wait for it, NOTHING! Can you call methods from nothingness? NO!
In a class of mine, I have a private field of type ExpandoObject. The field is initialized in the constructior (this.expected = new ExpandoObject()), so I'm confident that it will never be null.
Thus, in one of the methods on this class, I fell safe to add
Contract.Assumes(this.expected != null)
before using this.expected for anything, so Code Contracts won't have to worry about possible calls on null objects. However, instead of a warning for possible method call on a null reference, I get a warning saying
The dynamically dispatched call to method 'Assume' may fail at runtime because one or more applicable overloads are conditional method
The method signature and the first few lines of code looks like this:
protected void Expect(object values)
{
Contract.Requires<ArgumentNullException>(values != null);
Contract.Assume(this.expected != null);
var exp = (ICollection<KeyValuePair<string, object>>)this.expected;
On the third line, I get a warning for
CodeContracts: Possibly calling a method on a null reference 'OddEnds.Testing.TestBase.o_SiteContainer0.<>p_Site3.Target'
where I assume the odd signature of the null reference is because exp is a dynamic object.
How do I solve these?
I think the best way to solve your problem is to declare that expected is never null as an invariant on the class:
class TheClass {
ExpandoObject expected;
...
[ContractInvariantMethod]
void Invariants()
{
Contract.Invariant(this.expected != null);
}
...
}
When you do this, the static checker will check that expected is not null at the end of your constructor, and then it will know that expected is never null at the start of any other method.
Im thinking following code change will keep compiler happy (if your sure in this cast anyway, but why use expandoobject then.. anyway)
ICollection<KeyValuePair<string, object>> col = this.expected as ICollection<KeyValuePair<string, object>>;
Contract.Assume(col != null);