instruccion - C#: el rendimiento dentro de un foreach falla-el cuerpo no puede ser un bloque iterador
yield return c# stack overflow (4)
Solo puede usar el yield return
en una función que devuelve un IEnumerable
o un IEnumerator
, no un List<T>
.
IEnumerable<DesktopComputer>
cambiar su función para devolver un IEnumerable<DesktopComputer>
.
Alternativamente, puede reescribir la función para usar List<T>.ConvertAll
:
return GetComputerIdTags().ConvertAll(pcTag =>
new DesktopComputer() {
AssetTag = pcTag,
Description = "PC " + pcTag,
AcquireDate = DateTime.Now
});
Considera este bit de código confuso. La intención es crear un nuevo objeto sobre la marcha a través del constructor anónimo y yield return
. El objetivo es evitar tener que mantener una colección local simplemente para return
.
public static List<DesktopComputer> BuildComputerAssets()
{
List<string> idTags = GetComputerIdTags();
foreach (var pcTag in idTags)
{
yield return new DesktopComputer() {AssetTag= pcTag
, Description = "PC " + pcTag
, AcquireDate = DateTime.Now
};
}
}
Desafortunadamente, este bit de código produce una excepción:
Error 28 El cuerpo de ''Foo.BuildComputerAssets ()'' no puede ser un bloque de iterador porque ''System.Collections.Generic.List'' no es un tipo de interfaz de iterador
Preguntas
- que significa este mensaje de error?
- ¿Cómo puedo evitar este error y utilizar correctamente la
yield return
?
Su firma de método es incorrecta. Debería ser:
public static IEnumerable<DesktopComputer> BuildComputerAssets()
También puede implementar la misma funcionalidad utilizando una consulta LINQ (en C # 3.0+). Esto es menos eficiente que usar el método ConvertAll
, pero es más general. Más adelante, es posible que también deba usar otras funciones de LINQ, como el filtrado:
return (from pcTag in GetComputerIdTags()
select new DesktopComputer() {
AssetTag = pcTag,
Description = "PC " + pcTag,
AcquireDate = DateTime.Now
}).ToList();
El método ToList
convierte el resultado de IEnumerable<T>
a List<T>
. Personalmente no me gusta ConvertAll
, porque hace lo mismo que LINQ. Pero debido a que se agregó anteriormente, no se puede usar con LINQ (se debería haber llamado Select
).
yield solo funciona en los tipos de iterador:
La declaración de rendimiento solo puede aparecer dentro de un bloque iterador
Iterators se definen como
El tipo de retorno de un iterador debe ser IEnumerable, IEnumerator, IEnumerable <T> o IEnumerator <T>.
IList e IList <T> implementan IEnumerable / IEnumerable <T>, pero cada persona que llama a un enumerador espera uno de los cuatro tipos anteriores y ninguno más.