Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
812 views
in Technique[技术] by (71.8m points)

powershell - Why and how are these two $null values different?

Apparently, in PowerShell (ver. 3) not all $null's are the same:

    >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

So how and why is $l_t2 different from $l_t3? In particular, is $l_t2 really $null or not? Note that $l_t2 is NOT an empty array ($l_t1 is, and $l_t1 -eq $null returns nothing, as expected), but neither is it truly $null, like $l_t3. In particular, $l_t2.count returns 0 rather than an error, and furthermore, adding $l_t2 to $l_t behaves like adding an empty array, not like adding $null. And why does $l_t2 suddenly seem to become "more $null" when it gets passed in the the function addToArray as a parameter???????

Can anyone explain this behaviour, or point me to documentation that would explain it?

Edit: The answer by PetSerAl below is correct. I have also found this stackOverflow post on the same issue.

Powershell version info:

    >$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                                                                                          
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In particular, is $l_t2 really $null or not?

$l_t2 is not $null, but a [System.Management.Automation.Internal.AutomationNull]::Value. It is a special instance of PSObject. It is returned when a pipeline returns zero objects. That is how you can check it:

$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

I call ReferenceEquals thru Reflection to prevent conversion from AutomationNull to $null by PowerShell.

$l_t1 -eq $null returns nothing

For me it returns an empty array, as I expect from it.

$l_t2.count returns 0

It is a new feature of PowerShell v3:

You can now use Count or Length on any object, even if it didn’t have the property. If the object didn’t have a Count or Length property, it will will return 1 (or 0 for $null). Objects that have Count or Length properties will continue to work as they always have.

PS> $a = 42 
PS> $a.Count 
1

?

And why does $l_t2 suddenly seem to become "more $null" when it gets passed in the the function addToArray as a parameter???????

It seems that PowerShell converts AutomationNull to $null in some cases, like calling .NET methods. In PowerShell v2, even when saving AutomationNull to a variable it gets converted to $null.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...