Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

1K
Views
Usando GetEnumerator en PowerShell en IEnumerable implementado usando C# yield return

Tengo una API que devuelve IEnumerable<T> (o IEnumerable ), que se implementa internamente en C# mediante yield return .

Un ejemplo trivial:

 public class Class1 { public IEnumerable<int> Enumerate() { yield return 1; } }

En PowerShell, no puedo llamar a IEnumerable<T>.GetEnumerator en el enumerable devuelto por el método Enumerate() :

 $cls = New-Object Class1 $enumerable = $cls.Enumerate() Write-Host $enumerable.GetType() $enumerator = $enumerable.GetEnumerator()

Falla con:

No se puede encontrar una sobrecarga para "GetEnumerator" y el recuento de argumentos: "0".

El $enumerable.GetType() devuelve lo esperado:

Clase1+d__0

Un código idéntico en C# funciona como se esperaba.


Si el método se implementa usando un simple return :

 return new[] { 1 };

entonces no hay problema en PowerShell.


¿Por qué PowerShell no ve GetEnumerator() ?

Encontré esta pregunta algo relacionada: PowerShell/GetEnumerator , pero realmente no me da la respuesta/solución (o no la veo).


Para explicar, por qué quiero usar IEnumerator , en lugar de usar PowerShell foreach : quiero procesar el enumerable usando subprocesos paralelos que comenzaron con Start-ThreadJob . Y la enumeración es perezosa y requiere mucho tiempo. Por lo tanto, recopilar los resultados en algún contenedor antes de la enumeración tendría una penalización de rendimiento.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

El problema parece ser que el tipo IEnumerable<T> generado por el compilador implementa IEnumerable e IEnumerator<T> explícitamente :

 private sealed class <M>d__0 : IEnumerable<int>, IEnumerable, ... { [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { ... } [DebuggerHidden] IEnumerator<string> IEnumerable<int>.GetEnumerator() { ... } ... }

Los lenguajes enlazados en tiempo de ejecución generalmente tienen problemas con las interfaces implementadas explícitamente en .NET: después de todo, su enumerador es del tipo <M>d__0 , y ese tipo implementa dos métodos GetEnumerator() diferentes que devuelven cosas diferentes.

(No importa que obtuvo esa instancia de <M>d__0 llamando a un método que devolvió un IEnumerable<int> : los lenguajes enlazados en tiempo de ejecución se olvidan de ese bit de información de tipo).

El lenguaje debe proporcionar una sintaxis especial que le permita decir a qué versión de interfaz de GetEnumerator() desea llamar. IronPython, por ejemplo, le permitiría decir algo como :

 System.Collections.Generic.IEnumerable[int].GetEnumerator(enumerator)

No conozco ninguna sintaxis de PowerShell para hacer lo mismo (y mi búsqueda no encontró nada), en cambio, las personas parecen estar usando la reflexión :

 [System.Collections.Generic.IEnumerable[int]].GetMethod("GetEnumerator").Invoke($enumerable, $Null)
over 4 years ago · Santiago Trujillo Report

0

Para complementar la respuesta de @canton7: en lugar de usar el reflejo en PowerShell, es posible que desee modificar el código C# para usar una implementación implícita. Si desea seguir usando el yield return , puede agregar una clase contenedora que implemente la interfaz implícitamente sobre la implementación explícita generada.

Debe elegir qué interfaz desea implementar implícitamente, IEnumerable<T> o IEnumerable . Para un uso en PowerShell, probablemente no importe. El siguiente código implementa IEnumerable<T> implícitamente.

 internal class ImplicitEnumerable<T> : IEnumerable<T> { private readonly IEnumerable<T> _enumerable; public ImplicitEnumerable(IEnumerable<T> enumerable) { _enumerable = enumerable; } public IEnumerator<T> GetEnumerator() { return _enumerable.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }

Y utilízalo así:

 public class Class1 { public IEnumerable<int> Enumerate() { return new ImplicitEnumerable<int>(DoEnumerate()); } private IEnumerable<int> DoEnumerate() { yield return 1; } }
over 4 years ago · Santiago Trujillo Report

0

Desafortunadamente, el método de reflexión no funcionó para mí.

Pero logré enumerar a través de IEnumerable usando LINQ y el método ToArray(), así:

 $array = [Linq.Enumerable]::ToArray($enumerable)

Creo que la razón por la que la reflexión no funcionó es porque los elementos miembros de IEnumerable en mi caso eran objetos (de una clase personalizada) y no clases base como [int] o [string]

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!