Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

1K
Visualizações
Using GetEnumerator in PowerShell on IEnumerable implemented using C# yield return

I have an API that returns IEnumerable<T> (or IEnumerable), which is internally implemented in C# using yield return.

A trivial example:

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

In PowerShell, I cannot call IEnumerable<T>.GetEnumerator on the enumerable returned by the method Enumerate():

$cls = New-Object Class1

$enumerable = $cls.Enumerate()

Write-Host $enumerable.GetType()

$enumerator = $enumerable.GetEnumerator()

It fails with:

Cannot find an overload for "GetEnumerator" and the argument count: "0".

The $enumerable.GetType() returns expected:

Class1+d__0

An identical code in C# works as expected.


If the method is implemented using a plain return:

return new[] { 1 };

then there's no problem in PowerShell.


Why PowerShell does not see the GetEnumerator()?

I have found this somewhat related question: PowerShell/GetEnumerator, but it does not really give me the answer/solution (or I do not see it).


To explain, why I want to use the IEnumerator, instead of using PowerShell foreach: I want to process the enumerable using parallel threads started using Start-ThreadJob. And the enumeration is lazy and time intensive. So collecting the results to some container prior to the enumeration would have a performance penalty.

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

The problem appears to be that the compiler-generated IEnumerable<T> type implements IEnumerable and IEnumerator<T> explicitly:

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

    [DebuggerHidden]
    IEnumerator<string> IEnumerable<int>.GetEnumerator()
    {
        ...
    }

    ...
}

Late-bound languages typically have problems with explicitly implemented interfaces in .NET: after all your enumerator is of type <M>d__0, and that type implements two different GetEnumerator() methods which return different things.

(It doesn't matter that it got that instance of <M>d__0 by calling a method which returned an IEnumerable<int>: late-bound languages forget all about that bit of type information).

The language needs to provide special syntax to let you say which interface's version of GetEnumerator() you want to call. IronPython for example would let you say something like:

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

I'm not aware of any PowerShell syntax to do the same (and my searching didn't find anything), instead people seem to be using reflection:

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

0

To complement the @canton7's answer: Instead of using the reflection in PowerShell, you might want modify the C# code to use an implicit implementation. If you want to keep using the yield return, you can add a wrapper class that implements the interface implicitly on top of the generated explicit implementation.

You need to choose what interface you want to implement implicitly, the IEnumerable<T> or IEnumerable. For a use in PowerShell, it probably does not matter. The code below implements IEnumerable<T> implicitly.

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

And use it like this:

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 Relatório

0

Unfortunately the reflection method didn't work for me.

But I managed to enumerate through the IEnumerable by using LINQ and the method ToArray(), like so:

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

I think the reason why reflection did not work is because the member items of the IEnumerable in my case, were objects (of a custom class), and not base classes like [int] or [string]

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda