I have a very simple piece code which contains a foreach loop:
foreach(var item in list) {
var valueForPropertyA = getPropertyAValue(item?.Id ?? 0);
if(valueForPropertyA == null) {
continue;
}
item.PropertyA = new PropertyADto(valueForPropertyA);
}
We also have some automatic code inspection tool which gives me the following warning on the above code:
'item' is null on at least one execution path
Is it ever possible that an item in a list is null or am I misinterpreting the warning?
Sure, foreach doesn't skip items that are null. Then you'd get a NullReferenceException at the line item.PropertyA = new PropertyADto(valueForPropertyA);.
Instead you could use
foreach(var item in list.Where(i => i != null))
{
// ...
}
To answer your primary question, yes, if the IEnumerable being enumerated by the foreach loop contains reference types, they can be null. For example, List<string> may contain null entries, as string can be null.
I suspect the reason you are receiving the'item' is null on at least one execution path message is due to the use of the null propagating operator on the following line:
var valueForPropertyA = getPropertyAValue(item?.Id ?? 0);
Later on you call:
item.PropertyA = new PropertyADto(valueForPropertyA);
The first line's item?.Id indicates that you expect item might be null. The second line does not include the null propagating operator, so the code analysis tool is warning you that while item might be null on the first line, you are not handling this possibility on the second line.
Items of reference and nullable value types can be null - but you can skip them manually
foreach(var item in list.Where(x => x != null))
Related
See this sample:
var list = new List<string?>();
foreach (string item in list.Where(i => i != null))
{
if (item.Length == 2)
{
...
}
}
In this sample, I get possible null reference in two places. The foreach variable and the dereferencing of Length in if. The second one I can easily fix by adding a dammit (null-forgiving) operator like this: item!.Length
Is there any way to do the same thing to the first one? I know that I can mark it as nullable string and check again but, I have already checked.
When you apply filtering using Where, you eliminate all null values, but this doesn't change the type of values.
All you need is to cast the results after filtering to the proper type:
foreach (string item in list.Where(i => i != null).Select(x => x!))
Unfortunately the Where predicate doesn't modify the caller's view of whether items in the enumerable are null or not.
The approach given by Dmitry involves additional runtime overhead due to the use of an extra Select call.
You can avoid that overhead via this extension method:
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) where T : class
{
foreach (T? item in source)
{
if (item != null)
yield return item;
}
}
Your code then becomes:
foreach (string item in list.WhereNotNull())
{
if (item.Length == 2)
{
...
}
}
What is the best way to check for nulls in this situation?
foreach(var item in Vehicles.Car.CarModel)
{
...
...
}
Now the Car or CarModel can be Null and should be checked somehow. What is the best way?
You can write this to avoid some null checks in two lines before the loop:
TypeOfCarModel items = Vehicles?.Car?.CarModel ?? null;
if ( items != null )
foreach ( var item in items )
{
}
This use Null-conditional and Null-coalescing operators.
In case of a list, for example, or any other thing like that, a variant may be:
List<CarModelItem> items = Vehicles?.Car?.CarModel ?? new List<CarModelItem>();
foreach ( var item in items )
{
}
It avoids the null check because the "IEnumerable" is empty, but it creates an instance...
I'm getting a null exception while iterating over a collection of non nullable objects.
List<ReconFact> facts = new List<ReconFact>();
// ...populating facts
int count = 0;
foreach (var fact in facts)
{
Console.WriteLine(++count);
try
{
context = AddToContext(context, fact, count, 100, true);
}
catch (Exception e)
{
Console.WriteLine(e.Message); // Null Exception Raised at some point
}
}
How is that possible ? I didn't know that iterating over a list could provide null elements is that a normal behaviour ? Is it possible to add a null item when the list is populated ?
Yes, it's possible to add null to a List<T> where T is a reference type. Nothing prevents someone from:
List<ReconFact> facts = new List<ReconFact>();
facts.Add(null);
You could simply check that first:
foreach (var fact in facts.Where(f => f != null))
// ...
Yes, a List can contain nulls, so can arrays and several other collections.
It won't break the iterating itself, but it will break any code inside the { } that relies on the element not being null.
List<String> s = new List<String>();
s.Add("foo");
s.Add(null);
s.Add("bar");
Edit: Wait, what do you mean by "non-nullable objects"?
I think the problem is in your logic. You just initialize the list of Recontent named fact.
So all time its count is 0. Please check that.
I often come across code like the following:
if ( items != null)
{
foreach(T item in items)
{
//...
}
}
Basically, the if condition ensures that foreach block will execute only if items is not null. I'm wondering if the if condition is really needed, or foreach will handle the case if items == null.
I mean, can I simply write
foreach(T item in items)
{
//...
}
without worrying about whether items is null or not? Is the if condition superfluous? Or this depends on the type of items or maybe on T as well?
You still need to check if (items != null) otherwise you will get NullReferenceException. However you can do something like this:
List<string> items = null;
foreach (var item in items ?? new List<string>())
{
item.Dump();
}
but you might check performance of it. So I still prefer having if (items != null) first.
Based on Eric's Lippert suggestion I changed code to:
List<string> items = null;
foreach (var item in items ?? Enumerable.Empty<string>())
{
item.Dump();
}
Using C# 6 you could use the new null conditional operator together with List<T>.ForEach(Action<T>) (or your own IEnumerable<T>.ForEach extension method).
List<string> items = null;
items?.ForEach(item =>
{
// ...
});
The real takeaway here should be a sequence should almost never be null in the first place. Simply make it an invariant in all of your programs that if you have a sequence, it is never null. It is always initialized to be the empty sequence or some other genuine sequence.
If a sequence is never null then obviously you don't need to check it.
Actually there is a feature request on that here: https://github.com/dotnet/csharplang/discussions/1081#issuecomment-443209795
And the response is quite logical:
I think that most foreach loops are
written with the intent of iterating a
non-null collection. If you try
iterating through null you should get
your exception, so that you can fix
your code.
You could always test it out with a null list... but this is what I found on the msdn website
foreach-statement:
foreach ( type identifier in expression ) embedded-statement
If expression has the value null, a System.NullReferenceException is thrown.
You can encapsulate the null check in an extension method and use a lambda:
public static class EnumerableExtensions {
public static void ForEach<T>(this IEnumerable<T> self, Action<T> action) {
if (self != null) {
foreach (var element in self) {
action(element);
}
}
}
}
The code becomes:
items.ForEach(item => {
...
});
If can be even more concise if you want to just call a method that takes an item and returns void:
items.ForEach(MethodThatTakesAnItem);
It is not superflous. At runtime items will be casted to an IEnumerable and its GetEnumerator method will be called. That will cause a dereferencing of items that will fail
You do need this. You'll get an exception when foreach accesses the container to set up the iteration otherwise.
Under the covers, foreach uses an interface implemented on the collection class to perform the iteration. The generic equivalent interface is here.
The foreach statement of the C#
language (for each in Visual Basic)
hides the complexity of the
enumerators. Therefore, using foreach
is recommended instead of directly
manipulating the enumerator.
The test is necessary, because if the collection is null, foreach will throw a NullReferenceException. It's actually quite simple to try it out.
List<string> items = null;
foreach(var item in items)
{
Console.WriteLine(item);
}
the second will throw a NullReferenceException with the message Object reference not set to an instance of an object.
As mentioned here you need to check is it not null.
Do not use an expression that evaluates to null.
The accepted answer is getting old.
Nowadays, nullable types are used extensively and help the compiler understand what you're trying to achive (and avoid mistakes).
Which means that your list could be this :
List<Item>? list
...OR... this :
List<Item> list
You'll need to check for nullability only for the former case.
Same thing goes for items:
List<Item?> list
...OR... this :
List<Item> list
You'll need to check for nullability of items only for the former case.
And of course finally you have this :
List<Item?>? list
where anything (list and items) could potentially be null.
==================
EDIT: A picture is better than 1,000 words
In C# 6 you can write sth like this:
// some string from file or UI, i.e.:
// a) string s = "Hello, World!";
// b) string s = "";
// ...
var items = s?.Split(new char[] { ',', '!', ' ' }) ?? Enumerable.Empty<string>();
foreach (var item in items)
{
//..
}
It's basically Vlad Bezden's solution but using the ?? expression to always generate an array that is not null and therefore survives the foreach rather than having this check inside the foreach bracket.
So I frequently run into this situation... where Do.Something(...) returns a null collection, like so:
int[] returnArray = Do.Something(...);
Then, I try to use this collection like so:
foreach (int i in returnArray)
{
// do some more stuff
}
I'm just curious, why can't a foreach loop operate on a null collection? It seems logical to me that 0 iterations would get executed with a null collection... instead it throws a NullReferenceException. Anyone know why this could be?
This is annoying as I'm working with APIs that aren't clear on exactly what they return, so I end up with if (someCollection != null) everywhere.
Well, the short answer is "because that's the way the compiler designers designed it." Realistically, though, your collection object is null, so there's no way for the compiler to get the enumerator to loop through the collection.
If you really need to do something like this, try the null coalescing operator:
int[] array = null;
foreach (int i in array ?? Enumerable.Empty<int>())
{
System.Console.WriteLine(string.Format("{0}", i));
}
A foreach loop calls the GetEnumerator method.
If the collection is null, this method call results in a NullReferenceException.
It is bad practice to return a null collection; your methods should return an empty collection instead.
There is a big difference between an empty collection and a null reference to a collection.
When you use foreach, internally, this is calling the IEnumerable's GetEnumerator() method. When the reference is null, this will raise this exception.
However, it is perfectly valid to have an empty IEnumerable or IEnumerable<T>. In this case, foreach will not "iterate" over anything (since the collection is empty), but it will also not throw, since this is a perfectly valid scenario.
Edit:
Personally, if you need to work around this, I'd recommend an extension method:
public static IEnumerable<T> AsNotNull<T>(this IEnumerable<T> original)
{
return original ?? Enumerable.Empty<T>();
}
You can then just call:
foreach (int i in returnArray.AsNotNull())
{
// do some more stuff
}
It is being answer long back but i have tried to do this in the following way to just avoid null pointer exception and may be useful for someone using C# null check operator ?.
//fragments is a list which can be null
fragments?.ForEach((obj) =>
{
//do something with obj
});
Another extension method to work around this:
public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
{
if(items == null) return;
foreach (var item in items) action(item);
}
Consume in several ways:
(1) with a method that accepts T:
returnArray.ForEach(Console.WriteLine);
(2) with an expression:
returnArray.ForEach(i => UpdateStatus(string.Format("{0}% complete", i)));
(3) with a multiline anonymous method
int toCompare = 10;
returnArray.ForEach(i =>
{
var thisInt = i;
var next = i++;
if(next > 10) Console.WriteLine("Match: {0}", i);
});
Because a null collection is not the same thing as an empty collection. An empty collection is a collection object with no elements; a null collection is a nonexistent object.
Here's something to try: Declare two collections of any sort. Initialize one normally so that it's empty, and assign the other the value null. Then try adding an object to both collections and see what happens.
Just write an extension method to help you out:
public static class Extensions
{
public static void ForEachWithNull<T>(this IEnumerable<T> source, Action<T> action)
{
if(source == null)
{
return;
}
foreach(var item in source)
{
action(item);
}
}
}
It is the fault of Do.Something(). The best practice here would be to return an array of size 0 (that is possible) instead of a null.
Because behind the scenes the foreach acquires an enumerator, equivalent to this:
using (IEnumerator<int> enumerator = returnArray.getEnumerator()) {
while (enumerator.MoveNext()) {
int i = enumerator.Current;
// do some more stuff
}
}
I think the explanation of why exception is thrown is very clear with the answers provided here. I just wish to complement with the way I usually work with these collections. Because, some times, I use the collection more then once and have to test if null every time. To avoid that, I do the following:
var returnArray = DoSomething() ?? Enumerable.Empty<int>();
foreach (int i in returnArray)
{
// do some more stuff
}
This way we can use the collection as much as we want without fear the exception and we don't polute the code with excessive conditional statements.
Using the null check operator ?. is also a great approach. But, in case of arrays (like the example in the question), it should be transformed into List before:
int[] returnArray = DoSomething();
returnArray?.ToList().ForEach((i) =>
{
// do some more stuff
});
SPListItem item;
DataRow dr = datatable.NewRow();
dr["ID"] = (!Object.Equals(item["ID"], null)) ? item["ID"].ToString() : string.Empty;