Dav*_*osh 10 powershell null automation-null
显然,在PowerShell(第3版)中并非所有$null都是相同的:
>function emptyArray() { @() }
>$l_t = @() ; $l_t.Count
0
>$l_t1 = @(); $l_t1 -eq $null; $l_t1.count; $l_t1.gettype()
0
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
>$l_t += $l_t1; $l_t.Count
0
>$l_t += emptyArray; $l_t.Count
0
>$l_t2 = emptyArray; $l_t2 -eq $null; $l_t2.Count; $l_t2.gettype()
True
0
You cannot call a method on a null-valued expression.
At line:1 char:38
+ $l_t2 = emptyArray; $l_t2 -eq $null; $l_t2.Count; $l_t2.gettype()
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
>$l_t += $l_t2; $l_t.Count
0
>$l_t3 = $null; $l_t3 -eq $null;$l_t3.gettype()
True
You cannot call a method on a null-valued expression.
At line:1 char:32
+ $l_t3 = $null; $l_t3 -eq $null;$l_t3.gettype()
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
>$l_t += $l_t3; $l_t.count
1
>function addToArray($l_a, $l_b) { $l_a += $l_b; $l_a.count }
>$l_t = @(); $l_t.Count
0
>addToArray $l_t $l_t1
0
>addToArray $l_t $l_t2
1
Run Code Online (Sandbox Code Playgroud)
那么如何以及为何$l_t2与众不同$l_t3?特别是,$l_t2真的$null与否?请注意,这$l_t2不是一个空数组($l_t1是,并且$l_t1 -eq $null没有返回任何内容,如预期的那样),但它也不是真的$null,就像$l_t3.特别是,$l_t2.count将返回0而不是错误,此外,加入$l_t2以$l_t行为类似于添加一个空的阵列,不象添加$null.当它作为参数传递给函数时,为什么$l_t2突然变得"更多$null" addToArray????????
任何人都可以解释这种行为,或者指出可以解释它的文档吗?
编辑:以下PetSerAl的答案是正确的. 我也在同一个问题上找到了这个stackOverflow帖子.
Powershell版本信息:
>$PSVersionTable
Name Value
---- -----
WSManStackVersion 3.0
PSCompatibleVersions {1.0, 2.0, 3.0}
SerializationVersion 1.1.0.1
BuildVersion 6.2.9200.16481
PSVersion 3.0
CLRVersion 4.0.30319.1026
PSRemotingProtocolVersion 2.2
Run Code Online (Sandbox Code Playgroud)
use*_*407 16
特别是,
$l_t2真的$null与否?
$l_t2不是$null,但是[System.Management.Automation.Internal.AutomationNull]::Value.这是一个特例PSObject.管道返回零对象时返回.这是你如何检查它:
$a=&{} #shortest, I know, pipeline, that returns zero objects
$b=[System.Management.Automation.Internal.AutomationNull]::Value
$ReferenceEquals=[Object].GetMethod('ReferenceEquals')
$ReferenceEquals.Invoke($null,($a,$null)) #returns False
$ReferenceEquals.Invoke($null,($a,$b)) #returns True
Run Code Online (Sandbox Code Playgroud)
我ReferenceEquals通过反射来调用,以防止AutomationNullPowerShell 将转换为$ null.
$l_t1 -eq $null没有回报
对我来说,它返回一个空数组,正如我所期望的那样.
$l_t2.count返回0
这是PowerShell v3的新功能:
您现在可以在任何对象上使用Count或Length,即使它没有该属性.如果对象没有Count或Length属性,它将返回1(或$ null为$ null).具有Count或Length属性的对象将继续像往常一样工作.
Run Code Online (Sandbox Code Playgroud)PS> $a = 42 PS> $a.Count 1
当它作为参数传递给函数时,为什么
$l_t2突然变得"更多$null"addToArray????????
在某些情况下,PowerShell似乎转换AutomationNull为$null调用.NET方法.在PowerShell v2中,即使保存AutomationNull到变量,它也会转换为$null.
为了补充 PetSerAl的出色答案,我们提供了一个实用的摘要:
碰巧不产生任何输出的命令不会返回$null,而是[System.Management.Automation.Internal.AutomationNull]::Value单例,可以将其视为“数组值$null”,或者换句话说,为null数组。
@()也没有输出)(除非明确禁止枚举,例如使用Write-Output -NoEnumerate)。简而言之,这个特殊值的行为就像$null在标量上下文中一样,在数组 / 管道上下文中就像一个空数组,如下面的示例所示。
注意事项:
[System.Management.Automation.Internal.AutomationNull]::Value作为cmdlet /函数参数值传递时,始终会将其转换为$null。
在PSv3 +中,即使不是实际(标量)$null也不会在foreach循环中枚举;但是,它在管道中被枚举-参见底部。
在PSv2-中,将空数组保存在变量中会悄悄地将其转换为,$null并$null在foreach循环中(而不只是在管道中)进行枚举 -参见底部。
# A true $null value:
$v1 = $null
# An operation with no output returns
# the [System.Management.Automation.Internal.AutomationNull]::Value singleton,
# which is treated like $null in a scalar expression context,
# but behaves like an empty array in a pipeline or array expression context.
$v2 = & {} # calling (&) an empty script block ({}) produces no output
# In a *scalar expression*, [System.Management.Automation.Internal.AutomationNull]::Value
# is implicitly converted to $null, which is why all of the following commands
# return $true.
$null -eq $v2
$v1 -eq $v2
$null -eq [System.Management.Automation.Internal.AutomationNull]::Value
& { param($param) $null -eq $param } $v2
# By contrast, in a *pipeline*, $null and
# [System.Management.Automation.Internal.AutomationNull]::Value
# are NOT the same:
# Actual $null *is* sent as data through the pipeline:
# The (implied) -Process block executes once.
$v1 | % { 'input received' } # -> 'input received'
# [System.Management.Automation.Internal.AutomationNull]::Value is *not* sent
# as data through the pipeline, it behaves like an empty array:
# The (implied) -Process block does *not* execute (but -Begin and -End blocks would).
$v2 | % { 'input received' } # -> NO output; effectively like: @() | % { 'input received' }
# Similarly, in an *array expression* context
# [System.Management.Automation.Internal.AutomationNull]::Value also behaves
# like an empty array:
(@() + $v2).Count # -> 0 - contrast with (@() + $v1).Count, which returns 1.
# CAVEAT: Passing [System.Management.Automation.Internal.AutomationNull]::Value to
# *any parameter* converts it to actual $null, whether that parameter is an
# array parameter or not.
# Passing [System.Management.Automation.Internal.AutomationNull]::Value is equivalent
# to passing true $null or omitting the parameter (by contrast,
# passing @() would result in an actual, empty array instance).
& { param([object[]] $param)
[Object].GetMethod('ReferenceEquals').Invoke($null, @($null, $param))
} $v2 # -> $true; would be the same with $v1 or no argument at all.
Run Code Online (Sandbox Code Playgroud)
该[System.Management.Automation.Internal.AutomationNull]::Value文档指出:
任何不返回实际值的操作都应返回
AutomationNull.Value。任何评估Windows PowerShell表达式的组件都应准备好处理接收和丢弃此结果的过程。在需要值的评估中收到时,应将其替换为
null。
PSv2与PSv3 +和一般不一致之处:
PSv2在存储在变量中的值之间[System.Management.Automation.Internal.AutomationNull]::Value和之间没有区别:$null
使用无输出指令,直接在foreach声明中/管道没有如预期的工作 -什么是通过管道发送/在foreach没有输入回路:
Get-ChildItem nosuchfiles* | ForEach-Object { 'hi' }
foreach ($f in (Get-ChildItem nosuchfiles*)) { 'hi' }
Run Code Online (Sandbox Code Playgroud)相反,如果将无输出命令保存在变量中或使用了显式命令$null,则行为是不同的:
# Store the output from a no-output command in a variable.
$result = Get-ChildItem nosuchfiles* # PSv2-: quiet conversion to $null happens here
# Enumerate the variable.
$result | ForEach-Object { 'hi1' }
foreach ($f in $result) { 'hi2' }
# Enumerate a $null literal.
$null | ForEach-Object { 'hi3' }
foreach ($f in $null) { 'hi4' }
Run Code Online (Sandbox Code Playgroud)
PSV2:所有上述命令输出一个字符串开始的hi,因为$null 是通过管道发送/被列举foreach:
在PSv3 +不同,[System.Management.Automation.Internal.AutomationNull]::Value被转换为$null在分配给一个变量,并且$null是始终在PSV2列举。
PSv3 +:PSv3中的行为发生了变化,无论好坏:
好:没有通过管道为枚举命令发送$result:将foreach被循环不进入,因为[System.Management.Automation.Internal.AutomationNull]::Value被保存分配给一个变量时,与PSV2。
可能更糟: foreach不再枚举$null(无论是指定为文字还是存储在变量中),因此foreach ($f in $null) { 'hi4' }可能令人惊讶地未产生任何输出。
从好的方面来说,新行为不再枚举未初始化的变量,该变量的计算结果为$null(除非与一起被阻止Set-StrictMode)。
但是,一般而言,$null鉴于PSv2无法将空集合值存储在变量中,因此不枚举在PSv2中更为合理。
在总结中,PSv3 +行为:
带走区分的能力$null,并[System.Management.Automation.Internal.AutomationNull]::Value在上下文foreach声明
从而引入了与管道行为的不一致之处,在这种情况下要尊重这种区别。
为了向后兼容,无法更改当前行为。对此GitHub的评论提出了一种解决潜在不一致的潜在PowerShell版本的方法,这些版本不需要向后兼容。
| 归档时间: |
|
| 查看次数: |
738 次 |
| 最近记录: |