为什么PowerShell将`Where`的谓词应用于空列表 [英] Why is PowerShell applying the predicate of a `Where` to an empty list
问题描述
如果我在PowerShell中运行此程序,则希望看到输出0
(零):
If I run this in PowerShell, I expect to see the output 0
(zero):
Set-StrictMode -Version Latest
$x = "[]" | ConvertFrom-Json | Where { $_.name -eq "Baz" }
Write-Host $x.Count
相反,我收到此错误:
The property 'name' cannot be found on this object. Verify that the property exists and can be set.
At line:1 char:44
+ $x = "[]" | ConvertFrom-Json | Where { $_.name -eq "Baz" }
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
如果我在"[]" | ConvertFrom-Json
上放括号,它会变成这样:
If I put braces around "[]" | ConvertFrom-Json
it becomes this:
$y = ("[]" | ConvertFrom-Json) | Where { $_.name -eq "Baz" }
Write-Host $y.Count
然后它起作用".
在引入括号之前出了什么问题?
要解释作品"周围的引号-设置严格模式Set-StrictMode -Version Latest
表示我在$null
对象上调用了.Count
.这可以通过包装在@()
中来解决:
To explain the quotes around "works" - setting strict mode Set-StrictMode -Version Latest
indicates that I call .Count
on a $null
object. That is solved by wrapping in @()
:
$z = @(("[]" | ConvertFrom-Json) | Where { $_.name -eq "Baz" })
Write-Host $z.Count
我觉得这很不满意,但这是实际问题的一部分.
I find this quite dissatisfying, but it's an aside to the actual question.
推荐答案
PowerShell为什么将
Where
的谓词应用于空列表?
Why is PowerShell applying the predicate of a
Where
to an empty list?
因为ConvertFrom-Json
告诉Where-Object
不要尝试枚举其输出.
Because ConvertFrom-Json
tells Where-Object
to not attempt to enumerate its output.
因此,PowerShell尝试访问空数组本身上的name
属性,就像我们要做的那样:
Therefore, PowerShell attempts to access the name
property on the empty array itself, much like if we were to do:
$emptyArray = New-Object object[] 0
$emptyArray.name
将ConvertFrom-Json
括在括号中时,powershell会将其解释为分开的管道,该管道在 之前执行并结束.任何输出都可以发送到Where-Object
,并且<因此,c8>不能知道ConvertFrom-Json
希望它如此对待数组.
When you enclose ConvertFrom-Json
in parentheses, powershell interprets it as a separate pipeline that executes and ends before any output can be sent to Where-Object
, and Where-Object
can therefore not know that ConvertFrom-Json
wanted it to treat the array as such.
我们可以在Powershell中通过使用-NoEnumerate
开关参数集显式调用Write-Output
来重新创建此行为:
We can recreate this behavior in powershell by explicitly calling Write-Output
with the -NoEnumerate
switch parameter set:
# create a function that outputs an empty array with -NoEnumerate
function Convert-Stuff
{
Write-Output @() -NoEnumerate
}
# Invoke with `Where-Object` as the downstream cmdlet in its pipeline
Convert-Stuff | Where-Object {
# this fails
$_.nonexistingproperty = 'fail'
}
# Invoke in separate pipeline, pass result to `Where-Object` subsequently
$stuff = Convert-Stuff
$stuff | Where-Object {
# nothing happens
$_.nonexistingproperty = 'meh'
}
Write-Output -NoEnumerate
内部调用Cmdlet.WriteObject(arg, false)
,这反过来导致运行时不枚举与下游cmdlet(在您的情况下为Where-Object
)的参数绑定期间的arg
值.>
Write-Output -NoEnumerate
internally calls Cmdlet.WriteObject(arg, false)
, which in turn causes the runtime to not enumerate the arg
value during parameter binding against the downstream cmdlet (in your case Where-Object
)
为什么这是可取的?
Why would this be desireable?
在解析JSON的特定上下文中,此行为确实可能是理想的:
In the specific context of parsing JSON, this behavior might indeed be desirable:
$data = '[]', '[]', '[]', '[]' |ConvertFrom-Json
既然我已经向它传递了5个有效的JSON文档,我是否应该不期望ConvertFrom-Json
中有5个对象呢? :-)
Should I not expect exactly 5 objects from ConvertFrom-Json
now that I passed 5 valid JSON documents to it? :-)
这篇关于为什么PowerShell将`Where`的谓词应用于空列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!