Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am interfacing to an API that exposes the following function:
IEnumerable<Color?> getColors(long Id);
I call the function:
IEnumerable<System.Drawing.Color?> colList = getColors(1);
The list is not null when the function returns. However, when I attempt to iterate through the list:
foreach (System.Drawing.Color col in colList)
{...}
I get nothing. The loop is not entered.
What is the correct way to iterate through the list?
Edit: I finally figured out how to get a list count with this bit of voodoo:
int colCount = colList.Count<System.Drawing.Color?>();
The count is indeed zero, as has been suggested. I'm now off to the provider of the API to ask why so?
Thank you to all who provided positive and constructive suggestions.
The iterator is empty. That is why it does not enter the loop.
However, please note that you do not have a nullable type in your loop:
IEnumerable<System.Drawing.Color?> colList = getColors(1);
// System.Drawing.Color is not nullable:
foreach (System.Drawing.Color col in colList)
{
Console.WriteLine(col);
}
Which will result in an InvalidOperationException when a null comes (because it cannot cast null to System.Drawing.Color). Use a System.Drawing.Color? (or use var) instead.
Example:
static void Main()
{
foreach (var col in getColors(1))
{
Console.WriteLine(col == null);
}
Console.ReadLine();
}
static IEnumerable<System.Drawing.Color?> getColors(long Id)
{
yield return null;
}
Outputs True
About using the extension method Count, know that it might be iterating over the IEnumerable<Color?>※. In that case, I would suggest to use ToArray and check the size of the array. With that said, know that a IEnumerable<Color?> could also be infinite.
※: As per the reference source, Count could be casting to ICollection<TSource> or ICollection to get the Count property from there. Otherwise it will iterate.
Trivial example of infinite IEnumerable<Color?>:
static IEnumerable<System.Drawing.Color?> getColors(long Id)
{
while (true)
{
yield return null;
}
}
If you need to handle the empty case, another option is to set a variable inside the loop. If the variable is set, you know it is not empty.
Example:
bool isEmpty = true;
foreach (var col in getColors(1))
{
isEmpty = false;
// ...
}
if (isEmpty)
{
// ...
}
As Dmitry Bychenko points out, you might be interested in OfType.
Addendum:
The IEnumerable<T> interface has only a GetEnumerator method. However, C# supports extension methods, and you will find a large number of extension methods for IEnumerable<T> in System.Linq.Enumerable, including Count, ToArray and OfType.
To use these extension methods add using System.Linq; to your code file. Example:
using System.Linq;
// ...
static void Main()
{
var colors = getColors(1).ToArray();
// ...
}
Or call them as regular methods. Example:
static void Main()
{
var colors = System.Linq.Enumerable.ToArray(getColors(1));
// ...
}
These last two code examples are equivalent. Usually the former is prefered.
As you can see, Color? is nullable, when Color is not. If you want to get only not null values (Color), you can add Linq OfType<T>():
using System.Linq; // OfType<T>() is declared as Linq extension method
...
// loop over not null cols only
foreach (System.Drawing.Color col in colList.OfType<System.Drawing.Color>()) {
...
}
Demo:
using System.Linq;
...
List<System.Drawing.Color?> list = new List<System.Drawing.Color?>() {
System.Drawing.Color.Red,
System.Drawing.Color.Black,
null, // <- should be excluded
System.Drawing.Color.Blue,
};
foreach (System.Drawing.Color col in list.OfType<System.Drawing.Color>())
Console.WriteLine(col);
Outcome:
Color [Red]
Color [Black]
Color [Blue]
This is not in relation to the nullable values of the IEnumerable. If you run this code (https://rextester.com/):
List<String> list = new List<String>();
list.Add(null);
list.Add("asd1");
list.Add(null);
list.Add("asd2");
list.Add(null);
IEnumerable<String> enumerable = list.AsEnumerable();
foreach(var item in enumerable)
{
Console.WriteLine('"' + item + '"');
}
The output will be:
""
"asd1"
""
"asd2"
""
So as you can see the null values are not removed from the IEnumerable and we still iterate through the empty values. More than likely the IEnumerable is empty.
Related
I am aware that the yield keyword indicates that the method in which it appears is an iterator. I was just wondering how that works with something like List<T>.AddRange.
Let's use the below example:
static void Main()
{
foreach (int i in MyInts())
{
Console.Write(i);
}
}
public static IEnumerable<int> MyInts()
{
for (int i = 0; i < 255; i++)
{
yield return i;
}
}
So in the above example after each yield, a value is returned in the foreach loop in Main and is printed to the console.
If we change Main to this:
static void Main()
{
var myList = new List<int>();
myList.AddRange(MyInts());
}
how does that work? Does AddRange get called for each int returned by the yield statement or does it somehow wait for all 255 values before adding the entire range?
The implementation of AddRange will iterate over the IEnumerable input using the iterator's .MoveNext() method until all values have been produced by your yielding method. This can be seen here.
So myList.AddRange(MyInts()); is called once and its implementation forces MyInts to return all of it values before moving on.
AddRange exhausts all values of the iterator because of how is implemented, but the following hypothetic method would only evaluate the first value of the iterator:
public void AddFirst<T>(IEnumerable<T> collection)
{
Insert(collection.First());
}
An interesting experiment while you play around with this is to add a Console.WriteLine(i); line in your MyInts method to see when each number is generated.
Short answer: When you call AddRange, it will internally iterate every item in your IEnumerable and add to the list.
If you did something like this:
var myList = new List<int>();
myList.AddRange(MyInts());
foreach (int i in myList)
{
Console.Write(i);
}
Then your values would be iterated twice, from the start to the end:
Once when adding to your list
Then in your for loop
Playing a bit
Now, let's suppose you created your own extension method for AddRange like this:
public static IEnumerable<T> AddRangeLazily<T>(this ICollection<T> col, IEnumerable<T> values)
{
foreach (T i in values)
{
yield return i; // first we yield
col.Add(i); // then we add
}
}
Then you could use it like this:
foreach (int i in myList.AddRangeLazily(MyInts()))
{
Console.Write(i);
}
...and it would be iterated twice as well, without going from the start to the end both times. It would lazily add each value to the list/collection and at the same time allow you to do something else (like printing it to output) after every new item being added.
If you had some sort of logic to stop the adding to the list in the middle of the operation, this should be helpful somehow.
The downside if this AddRangeLazily is: values will only be added to the collection once you iterate over AddRangeLazily like my code sample. If you just do this:
var someList = new List<int>();
someList.AddRangeLazily(MyInts());
if (someList.Any())
// it wouldn't enter here...
...it won't add values at all. If you wanted that behaviour, you should use AddRange. Forcing the iterationg over AddRangeLazily method would work, though:
var someList = new List<int>();
someList.AddRangeLazily(MyInts());
if (someList.AddRangeLazily(MyInts()).Count())
// it would enter here...thus adding all values to the someList
...however, depending on how lazy is the method you calling, it wouldn't iterate everything. For example:
var someList = new List<int>();
someList.AddRangeLazily(MyInts());
if (someList.AddRangeLazily(MyInts()).Any())
// it would enter here, plus adding only the first value to someList
Since Any() is true as soon as any item exists, then Any() just needs one iterationg to return true, therefore it just needs the first item to be iterated over.
I actually don't remember having to do something like this, it was just to play around with yield.
Fiddle here!!!
Interesting question.
The behavior is different if the enumerable is for a class that implements ICollection, such as another list or an array, but let's say it doesn't since your example doesn't. AddRange() simply uses the enumerator to insert items into the list one at a time.
using(IEnumerator<T> en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Insert(index++, en.Current);
If the type of the enumerator is ICollection then AddRange first expands the list and then does a block copy.
If you want to see the code yourself:
https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,51decd510e5bfe6e
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Collection was modified; enumeration operation may not execute - why?
First off, I believe this is NOT a duplicate question, as the context here deals with Extension methods.
I am getting this exception when moving items from one list to another via an Extension method, and I'm a bit confused because the list I'm removing items from is not the list I'm iterating over.
For example, the extension method at a minimum would look like this:
public static void MoveItemsTo(this IList source, IList target, IList items)
{
foreach (var item in items) {
target.Add(item);
source.Remove(item);
}
}
This is method is then called like this:
myCollectionOne.MoveItemsTo(myCollectionTwo, itemsToMove);
I only receive the error if I attempt to remove the item from the source list... This is a bit confusing as the method is iterating over a different list. Something must be going on behind the scenes that I am unaware of...
Instead of using a foreach loop, use a regular for loop. You're actually removing an item from the items list, since that's what you're iterating through.
for (int i = 0; i < items.Count; i++)
{
target.Add(item);
source.Remove(source[i]);
}
On a side note, you could probably just clear the entire source list in one go after the for loop, if that is indeed what you're trying to accomplish.
This will return a new list that is the result of the item move from source to destination, without altering the source lists. This avoids the refence problem in the question by treating the sources lists as immutable lists.
void Main()
{
var a = new List<string>() { "a","b","c" };
var b = new List<string>() { "d" };
var c = a.MoveItemsTo(i=>i=="b",b);
c.Dump(); // { "d", "b" }
}
public static class Extensions
{
public static IEnumerable<T> MoveItemsTo<T>(this IEnumerable<T> source, Func<T,bool> Predicate,IEnumerable<T> DestSource)
{
var newList = new List<T>(DestSource);
newList.AddRange(source.Where(Predicate).ToList());
return newList;
}
}
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;
I have the following code:
newsplit.ToList().ForEach(x => x = "WW");
I would expect that all elements in the list are now "WW" but they are still the original value. How come? What do I have to do different?
Assuming that newsplit is an IEnumerable<string>, you want:
newsplit = newsplit.Select(x => "WW");
The code that you currently have is equivalent to the following:
foreach(string x in newsplit.ToList()) {
AssignmentAction(x);
}
...
public static void AssignmentAction(string x) {
x = "WW";
}
This method won't modify x because of the pass-by-value semantics of C# and the immutability of strings.
Other answers have explained why your current code doesn't work. Here's an extension method which would fix it:
// Must be in a static non-nested class
public static void ModifyEach<T>(this IList<T> source,
Func<T,T> projection)
{
for (int i = 0; i < source.Count; i++)
{
source[i] = projection(source[i]);
}
}
Then use like this:
newsplit.ModifyEach(x => "WW");
That will work with any implementation of IList<T> such as arrays and List<T>. If you need it to work with an arbitrary IEnumerable<T> then you've got a problem, as the sequence itself may not be mutable.
Using Select() is a more functional approach of course, but sometimes mutating an existing collection is worth doing...
The ForEach will allow you to manipulate the elements of the IEnumerable, but not change the reference of the element.
ie, this would set a Foo property of each element in the IEnumerable to the string "WW":
newsplit.ToList().ForEach(x => x.Foo = "WW");
However, you won't be able to modify the values inside the IEnumerable itself.
It's because the LINQ expression is creating Anonymous Types, and these are read-only. They can't be assigned to. Also, in a standard for each loop you cannot assign to a collection that is being enumerated. Try:
foreach (var item in newsplit)
{
item = "this won't work";
}
You can write like this:
newsplit = newsplit.Select(x => "WW").ToList();