C#: null warning even though it's not possible - c#

Ok so here I have this function that can return a null value in some cases. However, even when testing if it is before, it still says it might be null.
My code:
if (Account.FindAccount(usernameInput) == null) { return; }
if (Account.FindAccount(usernameInput).password == "1234") // warning CS8602: Dereference of a possibly null reference
{
//Do stuff
}

Is that FindAccount operation guaranteed to be idempotent? The compiler has no such guarantee. What it returns in one call it might not return in another.
More to the point... If you believe it will always return the same result for the same input, why are you invoking it twice? Just invoke it once and store the result:
var account = Account.FindAccount(usernameInput);
if (account == null) { return; }
if (account.password == "1234")
{
//Do stuff
}

Related

Dereference of a possible null reference C#

I have a C# method which throws the following warning on line await _socketClient.Start();:
CS8602: Dereference of a possibly null reference.
Method:
public async Task Connect()
{
if ((_socketClient == null) || (_socketClient != null && _socketClient.IsRunning))
return;
await _socketClient.Start();
}
I am not able to understand why the compiler is giving that warning even though I have made an explicit null check the line above it and returning back to the caller method?
Interestingly, if I simplify the method to do a plain simple null reference check, the warning goes away.
Modified Method (No warning):
public async Task Connect()
{
if (_socketClient == null)
return;
await _socketClient.Start();
}
However, I need the additional check as well and not sure what is the mistake I am doing over there for the warning to pop up.
Environment:
.Net 6.0 aspnet core application
Visual Studio 2022 IDE
Visual Studio only throws CS8602 when it detects the presence of "maybe-null".
Looks like you have it pretty much narrowed down, does refactoring it like below help at all?
public async Task Connect()
{
if ( _socketClient == null ) {
return;
} else if ( _socketClient.IsRunning ) {
return;
} else {
await _socketClient.Start();
}
}
The problem is that after || you are checking for null again, which makes the compiler "thinks" that _socketClient could be null when first check is false even though it is _socketClient == null
If it is written as follows, it does not warn about the nullability
public async Task Connect()
{
if (_socketClient is null || _socketClient.IsRunning)
return;
await _socketClient.Start();
}

Why does the else statement not get executed if one of the bool parameters for if is null?

I have this code snippet here:
public void ReDrawParallelLines(string lineName, string viewType)
{
var referenceLineOne = GetLineParams(viewType + ReferenceEnum.One.ToString() + linename);
var referenceLineTwo = GetLineParams(viewType + ReferenceEnum.Two.ToString() + linename);
if (lineName == referenceLineOne.lineParams.lineName)
{
//Do certain action with referencelineone
}
else if (lineName == referenceLineTwo.lineParams.lineName)
{
//Do same action but with referencelinetwo
}
}
I noticed that if referenceLineOne is null but I have referenceLineTwo, the else statement never gets executed. I'm not sure why? Doesn't it work such that if the bool fails the if then continue to the else and it should pass for the else. It just skips the inside if statement and the else condition entirely because the referenceLineOne is null. Why and how can I correct this check?
Basically, I am passing a line name and I want to check to see if it's equal to one of two lines I get from the GetLineParams function.
Since referenceLineOne is null, you will get an exception, which is why it bypasses the else if and jumps somewhere else.
You should do null checking like this
if (referenceLineOne != null && lineName == referenceLineOne.lineParams.lineName)
{
//Do certain action with referencelineone
}
or this if you use c#6
if (lineName == referenceLineOne?.lineParams.lineName)
{
//Do certain action with referencelineone
}

Can not check if an array is null

i have the folloiwng action method inside my asp.net mvc application:-
public ActionResult CustomersDetails(long[] SelectRight)
{
if (SelectRight == null)
{
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
RedirectToAction("Index");
}
else
{
var selectedCustomers = new SelectedCustomers
{
Info = SelectRight.Select(GetAccount)
};
return View(selectedCustomers);
}
return View();
}
But if the SelectRight Array is empty then it will bypass the if (SelectRight == null) check and it will render the CustomerDetails view and raise an exception on the following code inside the view
#foreach (var item in Model.Info) {
<tr>
So how can i make the null check works fine?
You have to return the result of RedirectToAction(..).
public ActionResult CustomersDetails(long[] SelectRight)
{
if (SelectRight == null)
{
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
return RedirectToAction("Index");
}
else
{
'...
You can change the condition to the following one:
...
if (SelectRight == null || SelectRight.Length == 0)
...
That should help.
EDIT
The important thing to note about the code above is that in c#, the or operator || is short circuiting. It sees that the array is null (statement is true) and does NOT attempt to evaluate the second statement (SelectRight.Length == 0) so no NPE is thrown.
You could check that it isn't null, and doesn't have a length of zero.
if (SelectRight == null || SelectRight.Length == 0) {
ModelState.AddModelError("", "Unable to save changes...");
return RedirectToAction("Index");
}
Above if-statement would catch both null-values and empty arrays.

Getting NullReferenceException in impossible situation (when checking for null)

I have a very simple check right at the beginning of one of my methods as follows:
public void MyMethod(MyClass thing)
{
if(thing == null)
throw new ArgumentNullException("thing");
//Do other stufff....
}
But I'm getting stacktraces (from Elmah in a production environment) which appears to indicate that the "if(thing == null)" line is throwing a NullReferenceException. The first 2 lines of the stack trace are something like:
System.Web.HttpUnhandledException: Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.NullReferenceException: Object reference not set to an instance of an object.
at MyLibrary.BL.AnotherClass.MyMethod(MyClass thing) in C:\Development\MyProject\trunk\MyLibrary.BL\AnotherClass.cs:line 100
MyClass is a fairly simple class with no operator overloads or anything like that, so I'm a bit stumped as to what is throwing the NullReferenceException!
Can anybody suggest scenarios that might cause this?
EDIT: I suspect "thing" might be null, but I really would expect an ArgumentNullException not a NullReferenceException - this is basically what this question is about. Is there maybe something that the framework or Elmah that is changing or mis-reporting the exception - or is the only explanation that the binaries are somehow out of date?
It is impossible for if (thing == null) to throw a NullReferenceException.
This means that something else is going on. It's time to start using your imagination in conjunction with a firm resolve to ignore the possibility that the if caused a problem.
The if statement can throw a NullReferenceException if MyClass defines the == operator incorrectly e.g.
class MyClass
{
int A {get;set;}
public static bool operator ==(MyClass a, MyClass b)
{
return a.A == b.A;
}
public static bool operator !=(MyClass a, MyClass b)
{
return !(a == b);
}
}
Looks like the exception is coming from something up the chain that calls MyMethod. MyMethod() is throwing the Exception and nothing above is handling it, so whatever web framework you're in is throwing the HttpUnhandledException.
I also encountered this impossible situation. It turned out to be due to the use of the as keyword, I have no idea why. I was using the SharpPdf library and had a line of code like this:
var destElement = annotDict.Elements["/Dest"] as PdfName;
if (destElement == null)
{
continue;
}
If I remove the as PdfName portion, it works. So I now have two levels of checking in my code:
var destElement = annotDict.Elements["/Dest"];
if (destElement == null)
{
continue;
}
var destElementName = destElement as PdfName;
if (destElementName == null)
{
continue;
}
thing is null.
That would cause it.
[EDIT]: Here's the code I tested with:
protected void Button3_Click(object sender, EventArgs e)
{
MyMethod(null);
}
public void MyMethod(String thing)
{
if (thing == null) // This caused the exception to be thrown.
throw new Exception("test");
//Do other stufff....
}

Refactoring exceptions for workflow

I am currently refactoring an application which uses exceptions for logic flow. The code is difficult to read and maintain and makes a S.O.L.I.D fanboy like myself cry when reading it (not to mention the longest catch block I've ever seen in my career).
My question is what pattern(s) could you use to make it easier to maintain or how would you go about refactoring?
public void CallExternalServices(ICriteria criteria)
{
try
{
someResult = ExternalService1.SomeMethod(criteria);
}
catch (Service1Exception service1Exception)
{
if (criteria.SomeValue == "1")
{
if (service1Exception.InnerException != null
&& service1Exception.InnerException.InnerException != null
&& service1Exception.InnerException.InnerException is TargetSystemException)
{
TargetSystemException targetSystemException = (TargetSystemException)service1Exception.InnerException.InnerException;
if (targetSystemException.ErrorStatus.IsServiceDownForMaintenance())
{
// Call internal method to perform some action
SendNotification("Service down for maintenance.")
}
}
}
else if (criteria.SomeValue == "2")
{
if (service1Exception.InnerException != null
&& service1Exception.InnerException.InnerException != null
&& service1Exception.InnerException.InnerException is TargetSystemException)
{
TargetSystemException tx = (TargetSystemException)service1Exception.InnerException.InnerException;
if (targetSystemException.ErrorStatus.IsBusy())
{
// Call to some internal method to perform an action
SendDifferentNotification()
criteria.SetSomeFlagToBe = true;
try
{
someResult = ExternalService2.SomeOtherMethod(criteria);
}
catch (Service2Exception service2Exception)
{
if (service2Exception.InnerException != null
&& service2Exception.InnerException.InnerException != null
&& service2Exception.InnerException.InnerException is TargetSystemException)
{
TargetSystemException tx = (TargetSystemException)service1Exception.InnerException.InnerException;
if (targetSystemException.ErrorStatus.HasNumberOfDailyTransactionsBeenExceeded())
{
// Call internal method to perform some action
SendNotification("Number of daily transactions exceeded.")
}
}
else if (service2Exception.InnerException != null
&& service2Exception.InnerException.InnerException != null
&& service2Exception.InnerException.InnerException is FaultException)
{
FaultException faultException = service2Exception.InnerException.InnerException as FaultException;
if (faultException.Detail != null
&& faultException.Detail.FaultMessage.Equals("SomeValueToCheckAgainst", StringComparison.OrdinalIgnoreCase))
{
return someResult;
}
else
{
throw service2Exception;
}
}
else
{
throw service2Exception;
}
}
if (someResult != null)
{
// perform another action
SomeActionInvoker.ExecuteAcitonAgainst(someResult);
}
}
}
else if (service1Exception.InnerException != null
&& service1Exception.InnerException.InnerException != null
&& service1Exception.InnerException.InnerException is FaultException)
{
FaultException faultException = service1Exception.InnerException.InnerException as FaultException;
if (faultException.Detail != null
&& faultException.Detail.FaultMessage.Equals("SomeOtherValueToCheckAgainst", StringComparison.OrdinalIgnoreCase))
{
return someResult;
}
else
{
throw service1Exception;
}
}
else
{
throw service1Exception;
}
}
}
}
All in all I think you would be helped by breaking up some stuff into some helper methods. For example, you could extract your checks that look like this
if (<exception-instance>.InnerException != null &&
<exception-instance>.InnerException.InnerException != null &&
<exception-instance>.InnerException.InnerException is <exception-type>)
Into a boolean method; you call code like this at least 3 times by my cursory glance.
Also, I would recommend extracting that second top-level case into an error-handling method; and perhaps its nested if statements.
Check out Working Effectively with Legacy Code by Michael Feathers, particularly Chapter 22 (I Need to Change a Monster Method and I Can't Write Tests for It). There are a lot of great techniques in there for situations like yours. Personally, in cases like this I usually end up extracting methods from sections of the longer methods, and getting rid of local variables that are used throughout the method; these are almost always trouble.
Start by refactoring the method into multiple methods. You've got waaaaaay too many levels of indentation going on.
After that, consider if some of the new methods could be extracted into other objects, and use an IoC-style approach rather than a procedural one.
That's kind of a high level answer, but I'm tired and don't have the energy to actually rework the code myself :)

Categories