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



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

什么有效

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

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哈希表中的值?

哈希表中的键是对象,而不是字符串。当您试图访问具有整数12的密钥"12"时,它找不到该条目,因为密钥不匹配。

但是,您使用的不是标准哈希表,而是排序的哈希表,该哈希表上有不同的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

摘要

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


推理

如TheIncorrible1的回答所示,.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必须将其装箱到一个对象中,才能将其放入哈希表中。因此,如果您在进行查找时也将整数参数框入对象中,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

这与TheIncorrible1的实验非常接近,只是您不需要将键类型为其他类型的字典定义为其他类型,然后将查找强制转换为匹配类型,您只需要通过强制转换为对象来访问它,因为您定义的键已经在内部发生了这种情况。

最新更新