How to avoid Nullreference exception when searching in List [duplicate] - c#

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 5 years ago.
I am trying to get a list item that contains a certain string and I am using this code:
string myListLine= myList.FirstOrDefault(stringToCheck => stringToCheck.Contains("mystring "));
All works well but if the list does not contain a particular string it throws an error:
object reference not set to an instance of an object
I think that I should somehow validate if the string first exists but not sure what would be the best approach.

if the list does not contain a particular string it throws an error:
That is not correct. The exception is thrown, because you have a null value inside your list! If all of your items in the list are valid strings then there will be no exception thrown. In this case FirstOrDefault will simply return null.
I think that I should somehow validate if the string first exists
You can check whether it is null the oldscool way first and combine it with an logical AND && with the Contains method
string myListLine= myList.FirstOrDefault(stringToCheck =>
stringToCheck != null && stringToCheck.Contains("mystring "));
This way the second Contains will not be evaluated if the first condition evaluates to FALSE

You can use the safe navigation operator and the null-coalescing operator to fix this:
System.Collections.Generic.List<string> myList = new System.Collections.Generic.List<string> { null, "Test123" };
string myListLine = myList.FirstOrDefault(stringToCheck => stringToCheck?.Contains("mystring ") ?? false);
The problem occurs if you're calling a method on a null list entry.
Note: If the list is empty FirstOrDefault returns null.
Hope that helps.

Your code simply goes through myList, for each item, it checks if it contains "mystring ".
Only reason you may get a null reference while running that line is your list myList is null. It wouldn't get any error if it is empty.
if you get a null reference after that line, that would mean that myListLine is null, which would mean myList did not contain any items that matched "mystring ".
To make sure you do not get a null reference error with myListLine you should check if it is null before accessing it by using something like this;
if( myListLine != null ){
<Do something to myListLine>
} else {
<list doesnt contain the correct string, alert user.>
}

I think this sample code of mine is one of the safest way by accessing the myList object. If it is null then return an indicator that value was not found or empty.
List<string> myList = new List<string>()
{
"name","adress","phoneNumber"
};
myList.RemoveAll(item => item == null);
string myListLine = myList.FirstOrDefault(stringToCheck => stringToCheck.Contains("myString")) ?? "Not found/Empty";

A variation:
var myList = new List<string>(){"foo","Bar", null,"the mystring"};
string myListLine = myList.FirstOrDefault(s => s == null? false : s.Contains("mystring"));
Same notes as already mentioned regarding FirstOrDefault being null if empty list or no match (does not Contains)

Related

Using Enumerable.Contains method for null item checking

Let's suppose I have a very simple IEnumerable that looks like this:
IEnumerable<string> foo = new[] { "Apple", null, "Orange" };
I would like to check if it contains a null item. Based on what I found with Google, I can do this as follows:
bool containsNull = foo.Any(item => item == null);
What about the Enumerable.Contains method? The following seems pretty obvious to me, but I've never seen it this way:
bool containsNull = foo.Contains(null);
Is there any problem with the previous expression that results in the Enumerable.Any method used instead?
It's true, in most of the cases Contains(null) will do the work. But there is a vulnerability for ArgumentNullException. An example can be:
string foo = "foo";
bool containsNull = foo.Contains(null); //throws exception
In your case, you've already set the generic type as string so it is safe to use Contains.
The "Contains" operator checks whether a specified element exists in the collection or not and returns a boolean.
"Any" checks whether any element satisfy given condition or not? In the following example, Any operation is used to check whether any student is teen ager or not.
In this case is better use "ANY"
yo can to visit https://www.tutorialsteacher.com/linq/linq-quantifier-operators

checking for ANY NULL object before ToLower

I have an object where a property may exist or may not exist.
if(response.AddressInformation.AddressResponses.Any(inf => inf.AddressResponse.matchCodeStatus.ToLower().Equals("usps_match")))
{
}
I have two array items of AddressResponse. First item has null for matchCodeStatus and thats where I get object not set to an instance exception. How can I achieve my target and escape this exception?
I tried to put a null check before my IF, but it didnt work
if(response.AddressInformation.AddressResponses.Any(inf => inf.AddressResponse.matchCodeStatus != null)
As of C# 6, you can also use a null conditional operator ?. :
inf => inf.AddressResponse.matchCodeStatus?.ToLower().Equals("usps_match"))

String Comparison Error when Searching Blank Fields

Searching through a column in a spreadsheet I notice that the second line will exception ("Nullable object must have a value.") when it comes across a blank field, however the first line will succeed. I have to add the Bool cast to the second line because otherwise I get "Cannot convert Nullable<bool> to bool". I assume this is the issue, but is there a way around that to allow blank fields to be checked?
keyFoundCell = _ws.Cells["a:a"].FirstOrDefault(cell => cell.Value?.ToString() == field.Key);
keyFoundCell = _ws.Cells["a:a"].FirstOrDefault(cell => (bool)cell.Value?.ToString().Equals(field.Key, StringComparison.OrdinalIgnoreCase));
In both EPPlus and Excel Interop you can read a cell's contents using the Text property instead of the Value property if you want to operate on the cell's visible contents and avoid nulls. Value returns an object which might be null, but Text returns the visible text as a string which can be empty but won't be null.
If we're using Value.ToString() or Value?.ToString() then chances are we'd be better off with Text because that's a giveaway that we want the text we see, not the value.
What's happening here is that the ?. operator will return null right away if the left hand side of the operator is null.
So, when cell.Value is null, the first line works because you're doing a direct comparison using the == operator, which will return a bool. In other words, null == field.Key returns false (unless field.Key is null, of course).
The second line does not work without a cast because if the value is null, then the ?. operator returns null and the rest of the line is ignored (.ToString() is never called). So the exception you're getting is due to the fact that the if condition must return a bool, yet it's returning a Nullable<bool> instead.
One way to fix this is to simply check for null first. This will not compare any objects where cell.Value == null:
keyFoundCell = _ws.Cells["a:a"].FirstOrDefault(cell =>
cell.Value != null &&
cell.Value.ToString().Equals(field.Key, StringComparison.OrdinalIgnoreCase));
Another way you can do this is to use the static Equals method of the string class, which will allow one or more null arguments. This will include results where cell.Value == null (and will return true for those cases where field.Key is also null):
keyFoundCell = _ws.Cells["a:a"].FirstOrDefault(cell =>
string.Equals(cell.Value?.ToString(), field.Key, StringComparison.OrdinalIgnoreCase));
maybe try:
keyFoundCell = _ws.Cells["a:a"].FirstOrDefault(cell => (bool?)cell.Value?.ToString().Equals(field.Key, StringComparison.OrdinalIgnoreCase)) ?? false;

Why doesn't a null cause a NullReferenceException when mapping to and from a null type?

I'm basically trying to iterate over a lot of data and transform a returned data query to a more limited object within a View Model.
Rather than do a huge section of code, I'm calling .ForEach() on a list, then adding a new entry to the view model's list.
This works great, but, there is one property (Address) that is optional.
When I reach the optional item, I get NullReferenceException if the item from the DB doesn't have an entry.
A code example is:
var tmp = _context.Person.Include(x => x.Address).ToList();
tmp.ForEach(x => vm.List.Add(new IndexListItem()
{
Name = x.Name,
Address = x.Address.FirstLine + " " + x.Address.SecondLine,
ID = x.ID
}));
I have since found out from a different answer on this site that if I change the address line so that it reads:
Address = x.Address?.FirstLine + " " + x.Address?.SecondLine,
The code now works when I hit a null entry in tmp.
I do not understand this as the Address property on tmp was already allowing nulls, and the Address property on the view model allows nulls, so, why does changing the line suddenly not return an error?
In addition, is the reason for me not having to do x.Address?.FirstLine? because that's a string and strings are already nullable?
A null reference exception in this particular case is caused when you are trying to access a property where the parent object is null itself.
x.Address.FirstLine
i.e. in your case Address is null.
It is not in regard to what you are trying to set (i.e. the destination view model).
The reason that this works:
x.Address?.FirstLine
..is because 'in the background' it's checking first to see if Address is null. If it isn't, then it returns FirstLine and if it is, then null is returned. It's semantically equivalent to:
if (x.Address == null)
{
return null;
}
else
{
return x.Address.FirstLine;
}
Here's a blog post about the introduction of the ?. operator in C# for some background reading: https://blogs.msdn.microsoft.com/jerrynixon/2014/02/26/at-last-c-is-getting-sometimes-called-the-safe-navigation-operator/
I do not understand this as the Address property on tmp was already allowing nulls, and the Address property on the view model allows nulls, so, why does changing the line suddenly not return an error?
You are mixing up saving data with loading data. When you save the data to the database, null is acceptable, but when you try to use the data, null is not.
The null conditional operator (?.) allows you to "shorten" an if statement, and it would be something similar to:
Address = x.Address?.FirstLine + " " + x.Address?.SecondLine,
string Address = "";
if (x.Address != null)
{
Address += x.Address.FirstLine;
}
// ....
Also, while not relevant to your problem, the code you are using is extremely ineffective, you are loading 2 tables to get just a few properties when you could get those properties directly from the database:
var vm = _context.Person
.Select(x => new IndexListItem
{
Name = x.Name,
Address = x.Address?.FirstLine + " " + x.Address?.SecondLine,
ID = x.ID
})
.ToList();
x.Address?.FirstLine where ? is null propogation operator this means if x.Address is null set null for the FirstLine.
null propogation equivalent code
if (x.Address == null)
return null
else
return x.Address.FirstLine
All reference type variables are nullable. hence, assigning null to reference types are always valid.
string is a reference-type in your example. therefore you do not get error because string x = null is valid
Your issue isn't that Address is null and you're trying to assign it to another property that allows null, it's that you're trying to access .FirstLine in something that's null.
If Address is null, then what you're trying to do with .FirstLine is the equivalent of null.FirstLine which doesn't work. Nothing can't hold something.
The ? notation you're using that works is only effecting Address, basically saying if Address is NOT null give me the value of .FirstLine, if it is null, then give me null.

If condition for ?? operator on null object

I have the following string list:
List<string> Emails = new List<string>();
Trying to see if it has any values, or return an empty string:
string Email = Emails[0] ?? "";
The above code throws an exception:
Index was out of range. Must be non-negative and less than the size of
the collection. Parameter name: index
But changing the ?? operator to a simple if statement, it works fine:
if (Emails.Count > 0)
Email = Emails[0];
else
Email = "";
What am I missing here?
When the list is empty, should Emails[0] not be null ?
Thanks.
I suggest to change it to:
string Email = Emails.FirstOrDefault() ?? "";
If your list is empty, Emails[0] is not null, it just doesn't exist.
Edit: that works for strings and ref types, if you do have a value type, for example int, you will get default(int) that is 0 as result of FirstOrDefault of empty collection
Emails[0] will try access first item of the list - that is why it throws exception.
You can use "readable" DefaultIfEmpty method for declaring "default" value if collection is empty
string Email = Emails.DefaultIfEmpty("").First();
string Email = Emails[0]
That is the problem. ?? only checks if whats on its left is null and acts accordingly.
You seem to have the misconception that an empty list has null stored at index 0. That is most definitely not the case. These two lists are semantically very different:
var emptyList = new List<string>();
var someList = new List<string>() { null };
In your code you are trying to access the item at position zero of an empty list. This is an index out of range exception because there is no such item. The exception is thrown before the ?? operator is even evaluated.
Using Emails[0] will throw exception as you access element 0 that is not exist
as Maksim suggested Emails.FirstOrDefault() will return null if the list is empty which you check by ?? coalesce operator

Categories

Resources