2014-03-12 63 views
5

我想了解@()數組構造函數的行爲,並且遇到了這個非常奇怪的測試。爲什麼空的PowerShell管道與空值不一樣?

看來,空管的值是「不完全」同爲$ null,即使它是當量$空

$x = 1,2,3,4 | ? { $_ -ge 3 } 
$y = 1,2,3,4 | ? { $_ -ge 5 } 
$z = $null 

"x is $x" 
"y is $y" 
"z is $z" 

if ($x -eq $null) {'x is null'} else {'x NOT null'} 
if ($y -eq $null) {'y is null'} else {'y NOT null'} 
if ($z -eq $null) {'z is null'} else {'z NOT null'} 

$ax = @($x) 
$ay = @($y) 
$az = @($z) 

"ax.length = " + $ax.length 
"ay.length = " + $ay.length 
"az.length = " + $az.length 

"az[0].GetType " 
$az[0].GetType() 

產生以下輸出

x is 3 4 
y is 
z is 
x NOT null 
y is null 
z is null 
ax.length = 2 
ay.length = 0 
az.length = 1 
az[0].GetType 
You cannot call a method on a null-valued expression. 
At line:18 char:5 
+  $az[0].GetType() 
+  ~~~~~~~~~~~~~~~~ 
    + CategoryInfo   : InvalidOperation: (:) [], RuntimeException 
    + FullyQualifiedErrorId : InvokeMethodOnNull 

所以$ az數組長度爲1,$ az [0]爲$ null。

但真正的問題是:$ y和$ z都可能是-eq $ null,但是當我用@(...)構造數組時,那麼一個數組是空的,另一個數組是空的包含一個$ null元素?

回答

5

在Frode F.的回答中,「無」是PowerShell中一個非常神奇的值 - 它被稱爲[System.Management.Automation.Internal.AutomationNull] :: Value。下面將同樣的工作:

$y = 1,2,3,4 | ? { $_ -ge 5 } 
$y = [System.Management.Automation.Internal.AutomationNull]::Value 

PowerShell將在大多數地方的價值AutomationNull.Value像$空,但不是無處不在。一個明顯的例子是在流水線:

$null | % { 'saw $null' } 
[System.Management.Automation.Internal.AutomationNull]::Value | % { 'saw AutomationNull.Value' } 

這將只打印:

saw $null 

注意表達本身的管道,即使你沒有一個管道字符,所以下面大體相當:

@($y) 
@($y | Write-Output) 

理解這一點,應該明確的是,如果$ y成立值AutomationNull.Value,沒有數據被寫入到管道,因此該數組爲空。

有人可能會問爲什麼$ null寫入管道。這是一個合理的問題。在某些情況下,腳本/ cmdlet需要在不使用異常的情況下指示「失敗」 - 因此「無結果」必須不同,$ null是用於這種情況的明顯值。

我從沒穿過其中一個需要知道,如果你有「沒有價值」或$空的情景運行,但如果你沒有,你可以使用這樣的事情:

function Test-IsAutomationNull 
{ 
    param(
     [Parameter(ValueFromPipeline)] 
     $InputObject) 

    begin 
    { 
     if ($PSBoundParameters.ContainsKey('InputObject')) 
     { 
      throw "Test-IsAutomationNull only works with piped input" 
     } 
     $isAutomationNull = $true 
    } 
    process 
    { 
     $isAutomationNull = $false 
    } 
    end 
    { 
     return $isAutomationNull 
    } 
} 

dir nosuchfile* | Test-IsAutomationNull 
$null | Test-IsAutomationNull 
+0

優秀的描述。我驚呆了,有不止一個null。進一步谷歌搜索後,我發現第三個:System.Management.Automation.Language.NullString。由於所有這些空值都是-eq $ null,我怎樣才能真正測試哪個null在變量中? (不是這是一個常見的要求!) –

+2

特殊的空值不是什麼新東西,例如有System.DBNull.Value。不過,PowerShell並不會將這些其他特殊的空值視爲null。 [NullString] :: Value -ne $ null。 –

+0

感謝您使用Test-IsAutomationNull進行更新。我發現你需要運行一個管道,檢測它不處理任何東西,並得出結論:它必須收到一個AutomationNull。我想這就是當語言開始使用魔法值時你得到的。乾杯。 –

4

您遇到此問題的原因是因爲$null是一個值。這是「沒有價值」,但它仍然是一種價值。

PS P:\> $y = 1,2,3,4 | ? { $_ -ge 5 } 

PS P:\> Get-Variable y | fl * 

#No value survived the where-test, so y was never saved as a variable, just as a "reference" 

Name  : y 
Description : 
Value  : 
Visibility : Public 
Module  : 
ModuleName : 
Options  : None 
Attributes : {} 


PS P:\> $z = $null 


PS P:\> Get-Variable z | fl * 

#Our $null variable is saved as a variable, with a $null value. 

PSPath  : Microsoft.PowerShell.Core\Variable::z 
PSDrive  : Variable 
PSProvider : Microsoft.PowerShell.Core\Variable 
PSIsContainer : False 
Name   : z 
Description : 
Value   : 
Visibility : Public 
Module  : 
ModuleName : 
Options  : None 
Attributes : {} 

方式@()作品,是它保證了結果的包裝(陣列)的內部被傳送出去。這意味着只要你有一個或多個對象,它就會把它包裝在一個數組中(如果它不像多個對象一樣在數組中)。

$y什麼都不是,它是一個參考,但沒有存儲可變數據。所以沒有什麼可以創建一個數組。 $z然而,IS是一個存儲的變量,沒有任何值(空對象)。由於該對象存在,數組構造函數可以使用該項目創建一個數組。

+0

感謝您的見解和關於@($ null)的澄清,但傑森解釋了兩個空值之間的差別好一點。乾杯。 –

相關問題