visual net for ejemplos collection asp array c# .net

c# - ejemplos - ¿Por qué.NET foreach loop lanza NullRefException cuando la colección es nula?



foreach collection c# (11)

Por lo tanto, con frecuencia me encuentro con esta situación ... donde Do.Something(...) devuelve una colección nula, así:

int[] returnArray = Do.Something(...);

Entonces, trato de usar esta colección así:

foreach (int i in returnArray) { // do some more stuff }

Solo tengo curiosidad, ¿por qué un bucle foreach no puede operar en una colección nula? Me parece lógico que 0 iteraciones se ejecuten con una colección nula ... en su lugar arroja una NullReferenceException . Alguien sabe por qué esto podría ser?

Esto es molesto ya que estoy trabajando con API que no tienen claro exactamente qué devuelven, así que termino con if (someCollection != null) todas partes ...

Editar: Gracias a todos por explicar que foreach usa GetEnumerator y que si no hay un enumerador para obtener, el foreach fracasará. Supongo que estoy preguntando por qué el lenguaje / tiempo de ejecución no puede o no hará una comprobación nula antes de tomar el enumerador. Me parece que el comportamiento aún estaría bien definido.


Bueno, la respuesta corta es "porque así es como lo diseñaron los diseñadores del compilador". De forma realista, sin embargo, su objeto de colección es nulo, por lo que no hay forma de que el compilador haga que el enumerador recorra la colección.

Si realmente necesita hacer algo como esto, intente con el operador coalescente nulo:

int[] array = null; foreach (int i in array ?? Enumerable.Empty<int>()) { System.Console.WriteLine(string.Format("{0}", i)); }


Creo que la explicación de por qué se lanza una excepción es muy clara con las respuestas proporcionadas aquí. Solo deseo complementarme con la forma en que suelo trabajar con estas colecciones. Porque, algunas veces, utilizo la colección más de una vez y tengo que probar si nulo cada vez. Para evitar eso, hago lo siguiente:

var returnArray = DoSomething() ?? Enumerable.Empty<int>(); foreach (int i in returnArray) { // do some more stuff }

De esta forma podemos usar la colección tanto como queramos sin temor a la excepción y no contaminar el código con declaraciones condicionales excesivas.

¿Usando el operador de verificación nula ?. es también un gran enfoque. Pero, en el caso de las matrices (como el ejemplo en la pregunta), debe transformarse en Lista antes:

int[] returnArray = DoSomething(); returnArray?.ToList().ForEach((i) => { // do some more stuff });


Es culpa de Do.Something() . La mejor práctica aquí sería devolver una matriz de tamaño 0 (que es posible) en lugar de un nulo.


Hay una gran diferencia entre una colección vacía y una referencia nula a una colección.

Cuando usa foreach , internamente, está llamando al método GetEnumerator () de IEnumerable. Cuando la referencia es nula, esto elevará esta excepción.

Sin embargo, es perfectamente válido tener un IEnumerable vacío o IEnumerable<T> . En este caso, foreach no "iterará" sobre nada (ya que la colección está vacía), pero tampoco arrojará, ya que este es un escenario perfectamente válido.

Editar:

Personalmente, si necesitas evitar esto, te recomendaría un método de extensión:

public static IEnumerable<T> AsNotNull<T>(this IEnumerable<T> original) { return original ?? Enumerable.Empty<T>(); }

A continuación, puede simplemente llamar:

foreach (int i in returnArray.AsNotNull()) { // do some more stuff }


Otro método de extensión para evitar esto:

public static void ForEach<T>(this IEnumerable<T> items, Action<T> action) { if(items == null) return; foreach (var item in items) action(item); }

Consumir de varias maneras:

(1) con un método que acepta T :

returnArray.ForEach(Console.WriteLine);

(2) con una expresión:

returnArray.ForEach(i => UpdateStatus(string.Format("{0}% complete", i)));

(3) con un método anónimo multilínea

int toCompare = 10; returnArray.ForEach(i => { var thisInt = i; var next = i++; if(next > 10) Console.WriteLine("Match: {0}", i); });


Porque detrás de escena foreach adquiere un enumerador, equivalente a esto:

using (IEnumerator<int> enumerator = returnArray.getEnumerator()) { while (enumerator.MoveNext()) { int i = enumerator.Current; // do some more stuff } }


Porque una colección nula no es lo mismo que una colección vacía. Una colección vacía es un objeto de colección sin elementos; una colección nula es un objeto inexistente.

Aquí hay algo que probar: declarar dos colecciones de cualquier tipo. Inicialice uno normalmente para que esté vacío, y asigne al otro el valor null . Luego intente agregar un objeto a ambas colecciones y vea qué sucede.


Se está respondiendo hace mucho tiempo, pero he tratado de hacer esto de la siguiente manera para evitar la excepción de puntero nulo y puede ser útil para alguien que usa el operador de verificación nula C #.

//fragments is a list which can be null fragments?.ForEach((obj) => { //do something with obj });


Simplemente escriba un método de extensión para ayudarlo:

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); } } }


Un bucle foreach llama al método GetEnumerator .
Si la colección es null , esta llamada al método da como resultado una NullReferenceException .

Es una mala práctica devolver una colección null ; sus métodos deberían devolver una colección vacía en su lugar.


SPListItem item; DataRow dr = datatable.NewRow(); dr["ID"] = (!Object.Equals(item["ID"], null)) ? item["ID"].ToString() : string.Empty;