Powershell中索引可迭代项的Duck类型

Powershell中索引可迭代项的Duck类型,powershell,duck-typing,Powershell,Duck Typing,与在集合上进行管道连接不同,有时更方便的做法是按程序循环遍历集合。为了避免根据输入区分$和$键/$值,最好使用更一致的键/值处理: 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=

与在集合上进行管道连接不同,有时更方便的做法是按程序循环遍历集合。为了避免根据输入区分
$和
$键
/
$值
,最好使用更一致的键/值处理:

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中寻找duck打字的原因

对于散列和对象,探测
.getIterator
.getEnumerator
是最简单/明显的方法(无论如何都不太记得哪个属于哪个):

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

  • .Get()
    看起来确实是独一无二的(至少不是哈希表或PSObject中的方法),但即使对于类型猜测来说,听起来也有点过于泛化
  • .Add()
    也可以是整数方法(?)
  • .GetUpperBound()
    等。已经有点过于具体了

那么,有没有一种标准方法会说“arrayish”,而不是其他数字索引值集合之间共享的东西?

如果您只想匹配数组:

PS> $x = 1..10
PS> $x.GetType().IsArray
True
或者您可以检查是否存在整数索引器:

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

直到今天才听说鸭子打字。非常酷的概念。
.GetUpperBound()
到底有什么问题?你是否只是想专门匹配数组类型,而不是“实现”它的东西?@Matt不,的确如此。我不太精通.NET类型。但是,如果在其他数组样式或列表类型中可以找到
.GetUpperBound
,那么这可能是一个很好的限定符。我真的在寻找类似类型的“偶然兼容性”。(虽然在我的情况下我并不需要它。只是想知道,是否/如何可行。)啊,好吧,那么你只想确保它只识别数字索引的
[array]
类型,而不是非数组类型的误报。我的问题标题可能会误导你。是的,我主要关心的是普通数组,但这个示例将/应该适用于其他列表类型。查看Set/LinkedList/Stack之类的类型也会类似(可能也有一个隐式索引)。现在,这更多的是关于从KeyValuePair存储区中识别值列表。当然,
.IsArray
是正确的,但我要找的不多。(虽然是IDK,但Powershell本身可能会将一些类型猜测浓缩到其中)内省和签名检查当然很有趣。尽管目标只是测试一个常用的命名方法名。那么,
.Item()
是否已经特定于列表/数组?(哈希和对象至少没有。)如果您有.NET对象ParameterizedProperty,则表示它是索引器。匿名索引器作为项生成,但您还需要检查它是否为整数索引器。所以这有点棘手,但我不知道更好的方法。
(Get-Member -InputObject $x -Name 'Item' -MemberType 'ParameterizedProperty').Definition -match '\(int index\)'