问题
为什么$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 + @{}))
为我们提供了一种完全安全的方式来添加哈希表,其中任一值都可能为空。
我试图找出确切的原因,但我不能确定。
我最初的信念是:
- 可能会发生一些 PowerShell 隐式类型强制,其中右侧的内容被强制转换为与左侧的类型匹配。 例如,
"1"+1
右边的 1 变成字符串,输出"11"
,但1+"1"
右边变成一个数字,输出2
。- 这绝对不会发生,否则
$null + @{}
会抛出转换错误,或者转换并执行 null + null = null,而不是像它那样输出空哈希表。
- 这绝对不会发生,否则
- 为数字以外的事物添加 A + B 对于数组连接等内容有一些基本规则,但除此之外,它将下降到下面的 .Net 框架,并将尝试执行像
A.op_Addition(B)
这样的方法调用,并且将由左侧的东西来说明当您尝试将右侧的东西添加到它时会发生什么。- 这确实发生了,但在这里没有发生。考虑一下
@{} + 0
告诉您哈希表只能添加到哈希表中。(谎言,您可以将其添加到空)。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
- 正在触发添加两个哈希表的 PowerShell 处理,即使规范没有说它会。$null + @{}
- 看起来有一个隐含的$null + x = x
规则,尽管规范似乎没有提到它,并且它可能依赖于实现。[<type>]$null
- 将$null转换为数值类型会导致 0(6.15 算术转换),但将其转换为其他任何内容(?)似乎会导致$null(不在规范中)。- 说
$null
没有类型的注释和链接链违反了PowerShell规范4.1.2"空类型",该规范说"空类型有一个实例,自动变量$null(§2.3.2.2),也称为空值。所以至少在术语上,它被描述为PowerShell中的一种类型,即使你不能对它进行GetType()。