【问题标题】:Behaviour of PowerShell when Combining HashTables组合哈希表时 PowerShell 的行为
【发布时间】:2026-01-17 06:35:01
【问题描述】:

问题

为什么$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 + @{})) 为我们提供了一种完全安全的方法来添加任何一个值都可能为空的哈希表。

【问题讨论】:

  • 类型转换 $null 产生 $null:([hashtable]$null) -eq $null 是 True。 $null + @{} 是有效的,因为添加到 $null 没有任何限制。
  • 啊;所以 null 是无类型的,即使强制转换。谢谢。有道理/奇怪的是不是我以前遇到过的情况。关于 C# 的相关答案:*.com/a/930155/361842

标签: powershell null hashtable powershell-5.0


【解决方案1】:

我试图找出确切的原因,但我不能确定。

我最初的信念是:

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

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

7.7.1 加法说明:加法运算符+的结果是通常后面两个操作数指定的值之和 已应用算术转换(第 6.15 节)。

通常的算术转换说:

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

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

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

7.7.4 哈希表连接说明:当两个操作数都指定哈希表时,二元+运算符创建一个新的哈希表 包含由左操作数指定的元素 立即由右操作数指定的元素。

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

第 7 节介绍说:

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

根据我在规范中看到的,PowerShell 似乎没有定义 $null + Hashtable 操作,+ 的相应方法是 op_Addition - 哈希表没有的方法,请参阅更早的错误代码 - 这不是抛出那个错误,不仅如此,而且在添加到 0 的情况下,错误来自右操作数而不是左操作数。

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

4.1.2 null 类型的特性未指定。


所以总结似乎是:

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

【讨论】: