为什么PowerShell将`Where`的谓词应用于空列表 [英] Why is PowerShell applying the predicate of a `Where` to an empty list

查看:100
本文介绍了为什么PowerShell将`Where`的谓词应用于空列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆