Dereference of a possibly null reference warning - c#

I have an object called conversationService.
When I try to call a method on the object I get a warning:
'conversationService' may be null here. CS8602: Dereference of a
possibly null reference.
The thing is, I don't think it can be null there. Is there something I'm missing and how can I get rid of this warning?
This is my code:
public string GetNextState(string input)
{
if (conversationService == null)
LoadConversationService();
List<ConversationResponse> responses = conversationService.PredictResponse(new Conversation(input));
return responses.First().Text;
}
public void LoadConversationService()
{
conversationService = new ConversationService();
}
Here is an image showing code with the warning:
Code showing a warning of a dereference of a possibly null reference
I know that I can write it as
conversationService!.PredictResponse();
but I think it introduces clutter that should not be needed.
I tried checking for a null reference and then handling it before my line of code that gets the warning. I expected it to make the compiler understand that it can not be null when the dereferencing occurs but it did not understand.

The reason why this is happening is that the conversationService was null when this class's constructor was initialized. To avoid this issue, you can directly create an instance of the conversationService object in the constructor of the class like this:
private ConversationService conversationService = new ConversationService();
public string GetNextState(string input)
{
List<ConversationResponse> responses = conversationService.PredictResponse(new Conversation(input));
return responses.First().Text;
}
This approach will prevent null warnings from occurring.
You could also wrap the conversationResponse in a Getter such as
public string GetNextState(string input)
{
List<ConversationResponse> responses = GetConversationService().PredictResponse(new Conversation(input));
return responses.First().Text;
}
public ConversationService GetConversationService()
{
if(conversationService == null) conversationService = new ConversationService();
return conversationService();
}
Alternatively, you can use the null forgiving operator (!) to suppress these warnings, as you were doing previously.

You are trying to access method from the nullable object, so the compiler warns you that conversationService may be null. You can write conversationService?.PredictResponse(...) to tell the compiler that you are expecting possible null.

Related

How to tell C# nullable type checker that a variable cannot be null after a function call returns?

Short Version
How to make the C# nullable type checking compiler realize that the variable customer cannot be null after the call returns:
Constraints.NotNull(customer);
.NET Fiddle: https://dotnetfiddle.net/ZcgRCV
Long Version
If i have code like:
#nullable enable
Customer? c;
...
Console.WriteLine(customer.FirstName);
The compiler will (correctly) warn me that customer might be null when i try to access .FirstName:
customer.FirstName ⇐ possible null dereference
Guard Constraint
I want to perform a guard, or a constraint that will tell the C# 8 nullable type checker that the value cannot be null. I'll call a function that guarantess that the variable cannot be null after the function returns:
#nullable enable
Customer? customer;
...
Constraint.NotNull(customer, "Customer"); //if this function returns customer is definitely not null
Console.WriteLine(customer.FirstName);
Where Constraint.NotNull is something like:
public static class Constraint
{
public static void NotNull(Object? o, String msg="")
{
if (o == null)
throw new Exception("Object cannot be null "+msg);
}
}
And the guard does its job; it raises an exception. But the compiler doesn't realize that customer cannot be null after Constrant.NotNull returns:
Another Example
A better example, i came across in some old code:
Customer? currentCustomer;
//...
EnsureCurrentCustomer();
DoSomethingWithIt(currentCustomer); // guaranteed not null because EnsureCurrentCustomer did it,
// but the compiler doesn't know that.
We need a way for EnsureCurrentCustomer to tell the C# 8 nullable type checker that the variable currentCustomer cannot be null after EnsureCurrentCustomer function returns.
How do?
Attempt 1: Null forgiving (!) operator
No. I want to work with the type system, not hide the land-mines (as Microsoft reminds you)
Attempt 2: https://stackoverflow.com/a/58282043/12597 (gives its own error)
Attempt 3: https://stackoverflow.com/a/65076221/12597 (No, see #1)
ChatGPT says the only way to do it is to use the JetBrains [NotNull] constraint; which i don't have access to.
If you just change the call site ever so slightly:
customer = Constraint.NotNull(customer, "Customer");
Then you can just do:
public static class Constraint {
public static T NotNull<T>(T? t, string? msg="") where T: notnull {
if (t is null) {
throw new Exception("Object cannot be null "+msg);
}
return t;
}
}
For the second example, assuming currentCustomer is a field, you can use MemberNotNull:
[MemberNotNull("currentCustomer")]
void EnsureCurrentCustomer() {
if (currentCustomer is null) {
throw new Exception(...);
}
}
If currentCustomer is instead a local variable and EnsureCurrentCustomer is actually a local function, then I would do something similar to Constraint.NotNull, i.e. changing the caller to:
currentCustomer = EnsureCurrentCustomer()
and just use a non nullable Customer for the return type.
This is achieved using the [NotNull] annotation on the argument being verified in your guard-clause method. A good reference for this is in the ArgumentNullException.ThrowIfNull static method. The summary of the NotNullAttribute says:
Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns.
You can also refer to xUnit's Assert.NotNull assertion, which does the same thing.

Under what circumstances will JsonConvert.DeserializeObject return null

The signature of the method JsonConvert.DeserializeObject() method in Newtonsoft.Json (Json.NET) is:
public static object? DeserializeObject(string value)
Source code here.
The method (and all its overloads) return a nullable object. I want to know under what circumstances will it return null? I was always under the impression that this method either throws Newtonsoft.Json.JsonException in case of unsuccessful deserialization or a properly constructed object in case of successful deserialization. The official documentation doesn't help in explaining the nullability either.
One possible circumstance might be that the exception was handled by a custom handler. Is there any other case that the method can return null?
var obj = JsonConvert.DeserializeObject<MyObject>("invalid json", new JsonSerializerSettings
{
Error = (sender, args) => args.ErrorContext.Handled = true
});
// obj is null here?
As mentioned by #Lasse V. Karlsen in the comments, the following code will return null
JsonConvert.DeserializeObject<SomeClass>("")
// or
JsonConvert.DeserializeObject<SomeClass>("null")
The same applies to the value of any property
JsonConvert.DeserializeObject<SomeClass>("{someProp : null}")
Note that an actual null string will throw an ArgumentNullException
JsonConvert.DeserializeObject<SomeClass>(null)

If an object is of specified Type, can it still be null?

If you check an object for its type and find out it is of the type you checked for, and you convert it to this type, can this type still be null after conversion ?
The code quality scanning app I'm running is complaining about the following:
if (tx.Tag is ExtendedNodeInfo && ty.Tag is ExtendedNodeInfo)
{
var tagX = tx.Tag as ExtendedNodeInfo;
var tagY = ty.Tag as ExtendedNodeInfo;
// HP Fortify scan says the below line's use of tagX/Y can be null.
// If I add null checks below for taX/Y, Resharper says
// its redundant as its always not null
return tagX.Ordinal.CompareTo(tagY.Ordinal);
}
If tx.Tag doesn't change its value, that's fine - but presumably the code quality scanner doesn't know that. It's generally better to use as for this, so that you only evaluate the property once, only perform the type test once, and then just check the references:
var tagX = tx.Tag as ExtendedNodeInfo;
var tagY = ty.Tag as ExtendedNodeInfo;
if (tagX != null && tagY != null)
{
return tagX.Ordinal.CompareTo(tagY.Ordinal);
}
if (tx.Tag is ExtendedNodeInfo && ty.Tag is ExtendedNodeInfo)
After this line, you have the following guarantees:
tx and ty are not null (otherwise, a NullReferenceException would have been thrown)
both tx.Tag and ty.Tag are of type ExtendedNodeInfo, so you can safely cast them to that type, so in your example both tagX and tagY are guarantueed to be not null
If the warning is about the use of txTag or tyTag, then this is wrong, IMO. But possibly, the warning is about the unchecked dereferencing of Ordinal?

initializing an object with strings to null

I have an object model somewhat like this:
public class MyObject
{
public string String1 { get; set; }
public string String2 { get; set; }
...
}
When the object initializes, all the string values are set to null.
Later on, I'm writing a method that evaluates the value of these strings to prepare an update in the DB. Something like this:
if (TheObject.String1 != null) { TheObjectInDB.String1 = TheObject.String1; }
if (TheObject.String2 != null) { TheObjectInDB.String2 = TheObject.String1; }
TheObject is an instance of MyObject and TheObjectInDB is an instance of the linq-to-sql map for the table I'm updating.
My question is this: is using the null a safe way to do it or could it cause problems later? Should I create a constructor that initializes these strings to "" and in the update check if the strings are = "" instead of = null?
Thanks for the advice.
There is nothing more, or less safe about null or an empty string. It is entirely your choice. Because both are often used to indicate the abscence of data or information, there is a convenience method string.IsNullOrEmpty that allows you to accept either value.
In your case, I would stick with the easiest option, null.
You could initialize both properties to string.Empty (preferred to "") and then check for string.Empty when setting the properties, however only if you can guarantee that either:-
a) the value being set is never string.Empty
or
b) the value being set is string.Empty but the values are only set once
I'd stick with checking for null to avoid either of the above causing potential issues in the future.
There is no problem here, the code you are using should work without any problems.
I can't even think of 'problems that this can cause 'later''.

ERROR PROMPT: Object reference not set to an instance of an object

public static string GetCurrentEmployeeName()
{
return db.Employees.SingleOrDefault(
c => c.NTUserName == CurrentUsername()
).Last_First;
}
There's no NULL data.
The default of a reference type is null, so if there is no matching record the SingleOrDefault method returns null.
Well, anything could be null in the above statement and you would get the above error.
db
Employees
c.NTUserName
You will have to debug through your code and find it out for yourself.

Categories

Resources