Powershell 中索引迭代对象的鸭子类型

Duck typing for indexed iteratables in Powershell

提问人:mario 提问时间:9/1/2017 更新时间:9/1/2017 访问量:173

问:

有时,与其在集合上进行管道处理,不如按程序循环访问它们会更方便。为了避免区分和/依赖于输入,更一致的键/值处理会很好:$_$_.Key$_.Value

ForEach-KV $object { Param($k, $v); do-stuff }

但是,常见的类型探测有其缺点:

#-- iterate over dicts/objects/arrays using scriptblock with Param($k,$v)
function ForEach-KV {
    Param($var, $cb, $i=0)
    switch ($var.GetType().Name) {
        Array          { $var | % { $cb.Invoke($i++, $_) } }
        HashTable      { $var.Keys | % { $cb.Invoke($_, $var[$_]) } }
       "Dictionary``2" { $var.Keys | % { $cb.Invoke($_, $var.Item($_)) } }
        PSobject       { $var.GetIterator() | % { $cb.Invoke($_.Key, $_.Value) } }
        PSCustomObject { $var.GetIterator() | % { $cb.Invoke($_.Key, $_.Value) } }
        default        { $cb.Invoke($i++, $_) }
    }
}

除了那个令人讨厌的类型名称之外,这里还有很多重复。这就是为什么我在 Powershell 中四处寻找鸭子类型的原因。

对于哈希和对象,探测 or 是最简单/显而易见的(无论如何都记不清哪个属于哪个):.getIterator.getEnumerator

switch ($_) {
    { $_.GetEnumerator }  { do-loopy }
    { $_.GetIterator }    { do-otherloopy }

但是现在我不太确定如何处理这里的数组。在方法中没有一个行为指标真正突出。[array]

  • .Get()确实看起来很独特(至少不是 HashTables 或 PSObjects 中的方法),但即使对于类型猜测来说听起来也有点太通用
  • .Add()还不如是一个整数方法(?
  • .GetUpperBound()等等,已经有点太具体了。

那么,有没有一种标准方法可以说“数组”,最好是在其他数字索引值集合之间共享的东西?

PowerShell 鸭子类型

评论

1赞 Matt 9/1/2017
直到今天才听说过鸭子打字。非常酷的概念。到底有什么问题?您是否只想专门匹配数组类型,而不是“实现”它的东西?.GetUpperBound()
0赞 mario 9/1/2017
@Matt 不,确实如此。我不太精通 .NET 类型。但是,如果可以在其他数组样式或列表类型中找到,那么这毕竟可能是一个很好的限定符。我真的在寻找与类似类型的“偶然兼容性”。(尽管就我而言,我真的不需要它。只是想知道,是否/如何可行。.GetUpperBound
0赞 Matt 9/1/2017
啊,好的,所以你只想确保它只识别数字索引类型,而不是非数组类型的误报。[array]
0赞 mario 9/2/2017
我的问题标题可能具有误导性。虽然是的,我主要关心的是常见数组,但该示例将/应该适用于其他列表类型。查看 .NET 文档:像 Set/LinkedList/Stack 这样的类型是相似的(并且可能也有一个隐式索引)。现在,这更多的是关于从 KeyValuePair 存储中辨别值列表

答:

1赞 fdafadf 9/1/2017 #1

如果只想匹配数组:

PS> $x = 1..10
PS> $x.GetType().IsArray
True

或者你可以检查是否有整数索引器:

(Get-Member -InputObject $x -Name 'Item' -MemberType 'ParameterizedProperty').Definition -match '\(int index\)'

评论

0赞 mario 9/2/2017
当然是正确的,但不是我想要的。(虽然 IDK,但 Powershell 本身可能会将某种类型猜测浓缩到那里)。- 当然,内省和签名检查很有趣。尽管目标只是测试一个通用名称的方法名称。那么已经特定于列表/数组了吗?(Hash 和 Object 至少没有它。.IsArray.Item()
1赞 fdafadf 9/2/2017
如果有 .NET 对象,则 ParameterizedProperty 表示它是索引器。匿名索引器生成为 Item,但您还需要检查它是否为整数索引器。所以这有点棘手,但我不知道更好的方法。