【问题标题】:How do I access values in an ordered PowerShell hash table using integer keys?如何使用整数键访问有序 PowerShell 哈希表中的值?
【发布时间】:2019-01-12 03:39:50
【问题描述】:

我的要求是在ordered 哈希表中存储整数键并使用这些整数键访问哈希表值。

什么有效

当我使用字符串键时,没问题:

cls

$foo=[ordered]@{}

$foo.add("12",1)
$foo.add("24",2)

write-host ("first item=" + $foo.Item("12"))
write-host ("second item=" + $foo.Item("24"))

输出:

first item=1
second item=2

使用括号失败

当我使用括号时,程序不会抛出异常,但它什么也不返回:

$fooInt=[ordered]@{}

$fooInt.add(12,1)
$fooInt.add(24,2)

write-host ("first item=" + $fooInt[12])
write-host ("second item=" + $fooInt[24])

输出:

first item=
second item=

使用 Item 方法失败

当我使用 Item 方法和整数键时,PowerShell 将整数键解释为索引而不是键:

$fooInt=[ordered]@{}

$fooInt.add(12,1)
$fooInt.add(24,2)

write-host ("first item=" + $fooInt.Item(12))
write-host ("second item=" + $fooInt.Item(24))

输出:

Exception getting "Item": "Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index"
At line:8 char:1
+ write-host ("first item=" + $fooInt.Item(12))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], GetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenGetting

Exception getting "Item": "Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index"
At line:9 char:1
+ write-host ("second item=" + $fooInt.Item(24))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [],  GetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenGetting

如何使用整数键访问 PowerShell 哈希表中的值?

【问题讨论】:

  • @TessellatingHeckler:不 - 请参阅上面标记为 Using Brackets Fails 的更新
  • 啊,我明白了;另一个(更糟糕的)选择是使用反射来挑选get_Item() 的正确重载并调用它。 $fooInt.GetType().GetMethods().where{$_.Name -eq 'get_Item' -and $_.GetParameters().name -eq 'Key'}.Invoke($fooInt, 'Public', $null, 1, $null)

标签: powershell key hashtable


【解决方案1】:

哈希表中的键是对象,而不是字符串。当您尝试使用整数 12 访问密钥 "12" 时,由于密钥不匹配,它无法找到该条目。

但是,您没有使用标准哈希表,您使用的是 ordered 哈希表,它具有不同的 Item 方法,因为它可以通过键 或索引。如果要使用有序哈希表访问整数键,则需要使用不同的语法:

$hash.12

如果使用数组访问器语法:

$hash[12]

它将尝试返回列表中的第 13 项。


您可以使用Get-Member观察这些对象之间的区别:

$orderedHash | Get-Member Item

   TypeName: System.Collections.Specialized.OrderedDictionary

Name MemberType            Definition
---- ----------            ----------
Item ParameterizedProperty System.Object Item(int index) {get;set;}, System.Object Item(System.Object key) {get;set;}

$hash | Get-Member Item

   TypeName: System.Collections.Hashtable

Name MemberType            Definition
---- ----------            ----------
Item ParameterizedProperty System.Object Item(System.Object key) {get;set;}

经过更多的实验,这只是int32 类型的情况。如果您使用不同的类型定义和访问它,它将起作用,因为它不再匹配重载的int 签名:

$hash = [ordered]@{
    ([uint32]12) = 24
}
$hash[[uint32]12]
> 24

【讨论】:

  • 感谢您的解释 - 很高兴了解内部信息:ordered 表和重载。使用 $fooInt.12$fooInt.24 访问表格效果很好
【解决方案2】:

总结

$fooInt.Item([object]12)$fooInt[[object]12]


推理

从 TheIncorrigible1 的回答中可以看出,.Item 有过载;它由 get_Item 方法支持:

PS C:\> $fooInt.get_Item

OverloadDefinitions
-------------------
System.Object get_Item(int index)
System.Object get_Item(System.Object key)
System.Object IOrderedDictionary.get_Item(int index)
System.Object IDictionary.get_Item(System.Object key)

采用整数并进行索引的版本来自IOrderedDictionary 接口,正常的IDictionary 键查找采用[System.Object]。当您尝试将它与整数参数一起使用时,PowerShell 会绑定采用 [int] 的版本,因为它是一个更好的匹配项,并运行该版本。

之前,我评论了如何使用反射来挑选所需的重载并调用它,但这很丑:

$fooInt.GetType().GetMethods().where{
        $_.Name -eq 'get_Item' -and $_.GetParameters().Name -eq 'Key'
    }.Invoke($fooInt, 'Public', $null, 12, $null)
                                        ^ your parameter

考虑一下,[int] 是值类型,而不是引用类型,这意味着 .Net 必须将其装箱到对象中才能将其放入 Hashtable 中。因此,如果您在查找时也将整数参数装箱到对象中,PowerShell 可能会绑定到您想要的重载并进行键查找并仍然匹配正确的键.. 你知道吗,它可以工作:

PS C:\> $fooInt=[ordered]@{}

PS C:\> $fooInt.add(12,1)
PS C:\> $fooInt.add(24,2)

PS C:\> write-host ("first item=" + $fooInt.Item([object]12))
first item=1

它也适用于索引:

PS C:\> write-host ("first item=" + $fooInt[[object]12])
first item=1

这与 TheIncorrigible1 的实验非常接近,除了您不需要使用键入的键定义字典然后将查找转换为匹配类型,您只需要通过转换为对象来访问它,因为对于您定义的键,这已经在内部发生了。

【讨论】:

  • [int] is a value type 从技术上讲,一切都是对象:耸耸肩:mklement0 也只编辑了我的答案;)
  • @TheIncorrigible1 请您原谅命名,我将其误读为您编辑的他的答案,并已将我的答案编辑为更正。如果它们是对象,为什么需要将它们装箱到供集合使用的对象中,为什么要引入泛型集合以通过避免装箱来减少开销?这似乎是一个argument without a clear answer,所以我已经编辑了我的答案的措辞,所以它不再这么说了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 2016-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多