在 IEnumerable 上使用 PowerShell 中的 GetEnumerator 使用 C# yield return

Mar*_*ryl 5 .net c# powershell ienumerable yield-return

我有一个返回IEnumerable<T>(或IEnumerable)的 API ,它是在 C# 中使用yield return.

一个简单的例子:

public class Class1
{
    public IEnumerable<int> Enumerate()
    {
        yield return 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

在 PowerShell 中,我无法调用IEnumerable<T>.GetEnumerator方法返回的可枚举Enumerate()

$cls = New-Object Class1

$enumerable = $cls.Enumerate()

Write-Host $enumerable.GetType()

$enumerator = $enumerable.GetEnumerator()
Run Code Online (Sandbox Code Playgroud)

它失败了:

找不到“GetEnumerator”和参数计数的重载:“0”。

$enumerable.GetType()收益预期:

Class1+d__0

C# 中的相同代码按预期工作。


如果该方法是使用普通实现的return

$cls = New-Object Class1

$enumerable = $cls.Enumerate()

Write-Host $enumerable.GetType()

$enumerator = $enumerable.GetEnumerator()
Run Code Online (Sandbox Code Playgroud)

那么在PowerShell中就没有问题了。


为什么 PowerShell 看不到GetEnumerator()?

我发现了这个有点相关的问题:PowerShell/GetEnumerator,但它并没有真正给我答案/解决方案(或者我没有看到)。


解释一下,为什么我要使用IEnumerator, 而不是使用 PowerShell foreach:我想使用从Start-ThreadJob. 并且枚举是惰性且耗时的。因此,在枚举之前将结果收集到某个容器会导致性能下降。

can*_*on7 1

问题似乎是编译器生成的IEnumerable<T>类型实现IEnumerableIEnumerator<T> 显式

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

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

    ...
}
Run Code Online (Sandbox Code Playgroud)

后期绑定语言通常在 .NET 中显式实现的接口方面存在问题:毕竟您的枚举器属于 类型<M>d__0,并且该类型实现了两种GetEnumerator()返回不同内容的不同方法。

<M>d__0(通过调用返回 : 的方法获得该实例并不重要IEnumerable<int>:后期绑定语言会忘记所有关于该类型信息的信息)。

该语言需要提供特殊的语法来让您说出GetEnumerator()要调用哪个接口的版本。例如,IronPython 会让你说这样的话

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

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

    ...
}
Run Code Online (Sandbox Code Playgroud)

我不知道任何 PowerShell 语法可以执行相同的操作(并且我的搜索没有找到任何内容),相反,人们似乎正在使用反射

[System.Collections.Generic.IEnumerable[int]].GetMethod("GetEnumerator").Invoke($enumerable, $Null)
Run Code Online (Sandbox Code Playgroud)