toodumbtocode
toodumbtocode

Reputation: 43

Object-Property assigned $null does not test true for $null

I've started using PowerShell to get some things done and played with the variable $null in PowerShell.

I've encountered the problem that when I assign the variable $null to a variable defined in a class, the test returns false not true.

Example Code:

class test {
    [string]$test1
}

$test = [test]::new()

$test.test1 = $null

$null -eq $test2 # tests true

$null -eq $test.test1 # tests false

Now the test of the undefinded variable $test2 returns true as every undefined variable in PowerShell is assigned $null.

But if I test the property test1 of the object test which I assigned $null tests false for $null

Is it because in PowerShell $null is an object with the value $null and now the property of the object is not $null as it has the object $null assigned to it with an empty value?

I've read into the docs of Microsoft "Everything you wanted to know about $null", but it does not enlighten me.

If I do not initialize the variable, then it will test true for $null.

Upvotes: 4

Views: 1062

Answers (3)

mklement0
mklement0

Reputation: 437111

To elaborate on robdy's helpful answer:

  • By design, [string]-typed variables, parameter variables, and custom-class properties in PowerShell do not store $null[1], only actual string values. Assigning $null always converts to '' (the empty string).

    • Below, $var receives '', not $null, due to being [string]-typed; therefore, the first -eq test fails and the second succeeds.

    • [string] $var = $null; $null -eq $var; '' -eq $var

    • Note that other .NET reference types (as opposed to value types, which fundamentally cannot be null) are not affected in PowerShell; that is, you can assign $null to them. Notably, this also applies to [object]. Note that not type-constraining a variable / parameter / property is the same as [object]-typing it.

  • That an uninitialized [string] property in a PowerShell class nonetheless currently defaults to $null should be considered a bug - see GitHub issue #7294.

    • The inconsistency becomes obvious if you explicitly initialize to $null, which again converts to '' and makes the test fail.

    • class test { [string]$test1=$null }; $null -eq [test]::new().test1

    • Should the bug be fixed and you truly need a $null value in a [string]-typed property - which is ill-advised in the context of PowerShell code - you'd have to use [NullString]::Value, as shown in the answer linked to below:
      class test { [string]$test1 = [NullString]::Value }; $null -eq [test]::new().test1

For more information, see this answer.


[1] The inability to store $null is a limitation that PowerShell imposes, in the interest of simplification. The underlying .NET type, System.String, typically does not have this limitation in other languages, notably not in C#.

Upvotes: 4

Moerwald
Moerwald

Reputation: 11254

If you're using a type contstraint like [string] or [int] Powershell initializes members at null-assignment with the default of the contrained type.

As @robdy states in above answer you've either check for the types default value or remove the constraint.

This may become more obvious if you're using a [int] type contstraint:

class test {
    [int]$i1 = 42
}
    
$test = [test]::new()
Write-Host $test.i1
$test.i1 = $null
Write-Host $test.i1
    

Output:

42
0

Upvotes: 3

Robert Dyjas
Robert Dyjas

Reputation: 5217

$test.test1 is not $null, it's empty string (because you explicitely defined it's value to be [string]):

C:\> $test.test1.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

Proof:

C:\> $test.test1 -eq ""
True

Upvotes: 4

Related Questions