组合HashTable时PowerShell的行为

时间:2017-06-09 16:43:48

标签: powershell null hashtable powershell-v5.0

问题

为什么$null + @{}有效,但@{} + $null没有;即使将null转换为哈希表(@{} + ([hashtable]$null))。

示例代码

[hashtable]$a = @{demo1=1;demo2='two'} 
[hashtable]$b = @{demo3=3;demo4='Ivy'} 
[hashtable]$c = $null

#combining 2 hashtables creates 1 with both hashes properties (would error if any properties were common to both)
write-verbose 'a + b' -Verbose
($a + $b)

#combining a null hashtable with a non-null hashtable works
write-verbose 'c + a' -Verbose
($c + $a)

#combing 2 null hashtables is fine; even if we've not explicitly cast null as a hashtable
write-verbose 'c + null' -Verbose
($c + $null)

#however, combinging a hashtable with null (i.e. same as second test, only putting null as the right argument instead of the left, produces an error
write-verbose 'a + c' -Verbose
($a + $c)

输出

Name                           Value                                                                                                                                                                                                                 
----                           -----                                                                                                                                                                                                                 
demo3                          3                                                                                                                                                                                                                     
demo4                          Ivy                                                                                                                                                                                                                   
demo1                          1                                                                                                                                                                                                                     
demo2                          two                                                                                                                                                                                                                   
VERBOSE: c + a
demo1                          1                                                                                                                                                                                                                     
demo2                          two                                                                                                                                                                                                                   
VERBOSE: c + d
VERBOSE: a + c
A hash table can only be added to another hash table.
At line:19 char:1
+ ($a + $c)
+ ~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : AddHashTableToNonHashTable

旁注

顺便说一下,这让我发现了这个哈希表的空合并操作的有用技巧:($c + @{})。例如($a + ($c + @{}))避免了上面产生的错误/ (($a + @{}) + ($c + @{}))为我们提供了一种完全安全的方法来添加哈希表,其中任何一个值都可以为空。

1 个答案:

答案 0 :(得分:2)

我试图找出原因,但我无法确定。

我最初的信念是:

  • 可能会发生一些PowerShell隐式类型强制,其中右侧的东西被强制转换为匹配左侧的类型。例如使用"1"+1,右侧的1变为字符串,输出为"11",但1+"1"右侧变为数字,输出为2
    • 这肯定没有发生,或者$null + @{}要么抛出一个强制转换错误,要么强制转换为null + null = null,而不是像它那样输出一个空的哈希表。
  • 为数字以外的东西添加A + B对于数组连接之类的事情有一些基本规则,但除此之外,它将落到下面的.Net Framework中并尝试执行像{{1}这样的方法调用这将取决于左边的事情,说明当你尝试将右边的东西添加到它时会发生什么。
    • 这确实发生了,但这里没有发生。考虑A.op_Addition(B)告诉您哈希表只能添加到哈希表中。 (谎言,你可以将它添加到null)。并且@{} + 0告诉您哈希表不包含0 + @{}方法。所以添加null似乎应该给出错误,但不会,因为它不会回到这个机制。

PSv3语言规范(我认为是最新版本),请点击此处下载:https://www.microsoft.com/en-us/download/details.aspx?id=36389,提及补充:

  

7.7.1加法描述:加法运算符+的结果是平时后两个操作数指定的值的总和   已应用算术转换(第6.15节)。

通常的算术转换说:

  

如果两个操作数都没有指定具有数字类型的值,则[..]指定值$ null的所有操作数都将转换为int类型的零,并且该过程将继续下面列出的数字转换。

这意味着在您的示例中,$ null将转换为0。虽然这不可能发生,因为op_Addition0 + @{}都是错误。

在第7.7节中明确提到添加两个哈希表:

  

7.7.4 Hashtable concatenation描述:当两个操作数指定Hashtables时,binary +运算符创建一个新的Hashtable   其中包含左操作数指定的元素   立即由右操作数指定的元素。

好的,散列表添加由PowerShell引擎处理,但只添加两个哈希表。

第7节介绍说:

  

Windows PowerShell:如果PowerShell未定义操作,则会检查左操作数指定的值的类型,以查看它是否具有相应的op_方法。

操作$ null + Hashtable似乎不是由我在规范中看到的PowerShell定义的,@{} + 0的相应方法是+ - 一个哈希表做的方法没有,请参阅前面的错误代码 - 这不是抛出错误,不仅如此,但在添加到0的情况下,错误来自右操作数而不是左操作数。

规范中另一个有趣的地方是:

  

4.1.2未指定null类型的特征。

所以摘要似乎是:

  • op_Addition - 触发PowerShell处理添加两个哈希表,即使规范没有说它会。
  • @{} + $null - 看起来有一个隐含的$null + @{}规则,虽然规范似乎没有提到它,但它可能依赖于实现。
  • $null + x = x - 将$ null转换为数字类型会导致0(6.15算术转换),但将其转换为其他任何内容(?)似乎会导致$ null(不在规范中)。
  • 注释和链接链表示[<type>]$null没有类型符合PowerShell规范4.1.2“null类型”,其中说“null类型有一个实例,自动变量$ null(§2.3。 2.2),也称为空值。这种类型的特征是未指定的。“所以至少在术语中,它被描述为PowerShell中的一种类型,即使你不能在其上使用GetType()..