PowerShell - "Write-Output" 与函数中的 "return"
PowerShell - "Write-Output" vs "return" in functions
我使用 PowerShell 已经很多年了,我认为我已经掌握了一些更 'eccentric' 的行为,但我遇到了一个我无法理解的问题尾巴...
我一直使用函数中的 "return" 到 return 值,但最近我想看看 Write-Output 作为替代方法。但是,PowerShell 就是 PowerShell,我发现了一些似乎没有意义的东西(至少对我而言):
function Invoke-X{ write-output @{ "aaa" = "bbb" } };
function Invoke-Y{ return @{ "aaa" = "bbb" } };
$x = Invoke-X;
$y = Invoke-Y;
write-host $x.GetType().FullName
write-host $y.GetType().FullName
write-host ($x -is [hashtable])
write-host ($y -is [hashtable])
write-host ($x -is [pscustomobject])
write-host ($y -is [pscustomobject])
输出:
System.Collections.Hashtable
System.Collections.Hashtable
True
True
True
False
$x 和 $y(或 'write-output' 和 'return')之间的区别是什么,这意味着它们都是哈希表,但其中只有一个“-是”pscustomobject?除了明显地检查我在变量中拥有的每个哈希表是否也是一个 pscustomobject 之外,是否有一种通用的方法可以确定与代码的区别)?
我的 $PSVersionTable 看起来像这样,以防此行为特定于特定版本的 PowerShell:
Name Value
---- -----
PSVersion 5.1.16299.492
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.16299.492
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
干杯,
男
return
和 [pscustomobject]
在某种程度上是转移注意力的东西。
归结为:
隐式表达式输出与cmdlet产生的输出;使用 return
(不调用 cmdlet)属于前一类,使用 Write-Output
属于后者。
输出对象被包装 - 大部分不可见 - [psobject]
实例仅在 cmdlet 中生成输出。
# Expression output: NO [psobject] wrapper:
@{ "aaa" = "bbb" } -is [psobject] # -> $False
# Cmdlet-produced output: [psobject]-wrapped
(Write-Output @{ "aaa" = "bbb" }) -is [psobject] # -> $True
请注意 - 令人惊讶的是 - [pscustomobject]
与 [psobject]
相同:它们都引用类型 [System.Management.Automation.PSObject]
,这是 通常不可见的辅助类型 [= PowerShell 在幕后使用的 105=]。
(更让人困惑的是, 是 一个单独的 [System.Management.Automation.PSCustomObject]
类型。)
在大多数情况下,这个额外的 [psobject]
包装器是良性的 - 它的大部分行为与包装对象直接一样 - 但在某些情况下它会导致微妙的不同行为(见下文)。
And is there a generalised way I can determine the difference from code, other than obviously checking whether every hashtable I have in a variable is also a pscustomobject
请注意,散列表 不是 一个 PS 自定义对象 - 它仅以这种方式出现 - 任何 - [psobject]
-wrapped 对象由于 [pscustomobject]
等同于 [psobject]
.
检测真正的 PS 自定义对象 - 使用 [pscustomobject] @{ ... }
或 New-Object PSCustomObject
/ New-Object PSObject
创建或由 Select-Object
和 Import-Csv
- 使用:
$obj -is [System.Management.Automation.PSCustomObject] # NOT just [pscustomobject]!
请注意,从 Windows PowerShell v5.1 / PowerShell Core v6.1.0 开始,将相关 -as
运算符与真正的 PS 自定义对象一起使用已被破坏 - 见下文。
作为额外 [psobject]
包装器是良性的情况的示例,您仍然可以直接测试包装对象的类型:
(Write-Output @{ "aaa" = "bbb" }) -is [hashtable] # $True
也就是说,尽管有包装器,-is
仍然可以识别 wrapped 类型。
因此,有些矛盾的是,在这种情况下,-is [psobject]
和-is [hashtable]
return$True
,即使这些类型是不相关的。
这些差异没有充分的理由,它们给我的印象是有漏洞的抽象(实现):内部构造不小心从幕后偷看。
以下 GitHub 个问题讨论了这些行为:
另请注意,与 .net 不同,添加 Write-Output
调试消息会将 return 类型更改为数组。添加写入行会破坏函数。
function Invoke-X {
$o1 = [pscustomobject] @{ foo = 1, 2 }
return $o1
}
function Invoke-Y {
$o1 = [pscustomobject] @{ foo = 1, 2 }
Write-Output "Debug messageY"
return $o1
}
function Invoke-Z {
$o1 = [pscustomobject] @{ foo = 1, 2 }
Write-Output "Debug messageZ"
return ,$o1
}
$x = Invoke-X;
$y = Invoke-Y;
$z = Invoke-Z;
Write-Host
Write-Host "X Type: " $x.GetType().FullName $x.foo
Write-Host
Write-Host "Y Type: " $y.GetType().FullName
Write-Host "Y0 Type: " $y[0].GetType().FullName $y[0]
Write-Host "Y1 Type: " $y[1].GetType().FullName $y[1].foo
Write-Host
Write-Host "Z Type: " $z.GetType().FullName
Write-Host "Z0 Type: " $z[0].GetType().FullName $z[0]
Write-Host "Z1 Type: " $z[1].GetType().FullName $z[1].foo
给出:
X Type: System.Management.Automation.PSCustomObject 1 2
Y Type: System.Object[]
Y0 Type: System.String Debug messageY
Y1 Type: System.Management.Automation.PSCustomObject 1 2
Z Type: System.Object[]
Z0 Type: System.String Debug messageZ
Z1 Type: System.Management.Automation.PSCustomObject 1 2
我使用 PowerShell 已经很多年了,我认为我已经掌握了一些更 'eccentric' 的行为,但我遇到了一个我无法理解的问题尾巴...
我一直使用函数中的 "return" 到 return 值,但最近我想看看 Write-Output 作为替代方法。但是,PowerShell 就是 PowerShell,我发现了一些似乎没有意义的东西(至少对我而言):
function Invoke-X{ write-output @{ "aaa" = "bbb" } };
function Invoke-Y{ return @{ "aaa" = "bbb" } };
$x = Invoke-X;
$y = Invoke-Y;
write-host $x.GetType().FullName
write-host $y.GetType().FullName
write-host ($x -is [hashtable])
write-host ($y -is [hashtable])
write-host ($x -is [pscustomobject])
write-host ($y -is [pscustomobject])
输出:
System.Collections.Hashtable
System.Collections.Hashtable
True
True
True
False
$x 和 $y(或 'write-output' 和 'return')之间的区别是什么,这意味着它们都是哈希表,但其中只有一个“-是”pscustomobject?除了明显地检查我在变量中拥有的每个哈希表是否也是一个 pscustomobject 之外,是否有一种通用的方法可以确定与代码的区别)?
我的 $PSVersionTable 看起来像这样,以防此行为特定于特定版本的 PowerShell:
Name Value
---- -----
PSVersion 5.1.16299.492
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.16299.492
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
干杯,
男
return
和 [pscustomobject]
在某种程度上是转移注意力的东西。
归结为:
隐式表达式输出与cmdlet产生的输出;使用
return
(不调用 cmdlet)属于前一类,使用Write-Output
属于后者。输出对象被包装 - 大部分不可见 -
[psobject]
实例仅在 cmdlet 中生成输出。
# Expression output: NO [psobject] wrapper:
@{ "aaa" = "bbb" } -is [psobject] # -> $False
# Cmdlet-produced output: [psobject]-wrapped
(Write-Output @{ "aaa" = "bbb" }) -is [psobject] # -> $True
请注意 - 令人惊讶的是 - [pscustomobject]
与 [psobject]
相同:它们都引用类型 [System.Management.Automation.PSObject]
,这是 通常不可见的辅助类型 [= PowerShell 在幕后使用的 105=]。
(更让人困惑的是, 是 一个单独的 [System.Management.Automation.PSCustomObject]
类型。)
在大多数情况下,这个额外的 [psobject]
包装器是良性的 - 它的大部分行为与包装对象直接一样 - 但在某些情况下它会导致微妙的不同行为(见下文)。
And is there a generalised way I can determine the difference from code, other than obviously checking whether every hashtable I have in a variable is also a pscustomobject
请注意,散列表 不是 一个 PS 自定义对象 - 它仅以这种方式出现 - 任何 - [psobject]
-wrapped 对象由于 [pscustomobject]
等同于 [psobject]
.
检测真正的 PS 自定义对象 - 使用 [pscustomobject] @{ ... }
或 New-Object PSCustomObject
/ New-Object PSObject
创建或由 Select-Object
和 Import-Csv
- 使用:
$obj -is [System.Management.Automation.PSCustomObject] # NOT just [pscustomobject]!
请注意,从 Windows PowerShell v5.1 / PowerShell Core v6.1.0 开始,将相关 -as
运算符与真正的 PS 自定义对象一起使用已被破坏 - 见下文。
作为额外 [psobject]
包装器是良性的情况的示例,您仍然可以直接测试包装对象的类型:
(Write-Output @{ "aaa" = "bbb" }) -is [hashtable] # $True
也就是说,尽管有包装器,-is
仍然可以识别 wrapped 类型。
因此,有些矛盾的是,在这种情况下,-is [psobject]
和-is [hashtable]
return$True
,即使这些类型是不相关的。
这些差异没有充分的理由,它们给我的印象是有漏洞的抽象(实现):内部构造不小心从幕后偷看。
以下 GitHub 个问题讨论了这些行为:
另请注意,与 .net 不同,添加 Write-Output
调试消息会将 return 类型更改为数组。添加写入行会破坏函数。
function Invoke-X {
$o1 = [pscustomobject] @{ foo = 1, 2 }
return $o1
}
function Invoke-Y {
$o1 = [pscustomobject] @{ foo = 1, 2 }
Write-Output "Debug messageY"
return $o1
}
function Invoke-Z {
$o1 = [pscustomobject] @{ foo = 1, 2 }
Write-Output "Debug messageZ"
return ,$o1
}
$x = Invoke-X;
$y = Invoke-Y;
$z = Invoke-Z;
Write-Host
Write-Host "X Type: " $x.GetType().FullName $x.foo
Write-Host
Write-Host "Y Type: " $y.GetType().FullName
Write-Host "Y0 Type: " $y[0].GetType().FullName $y[0]
Write-Host "Y1 Type: " $y[1].GetType().FullName $y[1].foo
Write-Host
Write-Host "Z Type: " $z.GetType().FullName
Write-Host "Z0 Type: " $z[0].GetType().FullName $z[0]
Write-Host "Z1 Type: " $z[1].GetType().FullName $z[1].foo
给出:
X Type: System.Management.Automation.PSCustomObject 1 2 Y Type: System.Object[] Y0 Type: System.String Debug messageY Y1 Type: System.Management.Automation.PSCustomObject 1 2 Z Type: System.Object[] Z0 Type: System.String Debug messageZ Z1 Type: System.Management.Automation.PSCustomObject 1 2