Consider the following code:
function f {
param (
[AllowNull()]
[string]
$x
)
return $x
}
$r = f -x $null
$null
is converted to [string]::Empty
by the time return
is reached. $null
is different from [string]::Empty
and I'd like to preserve this distinction. I'd also prefer to keep $x
as type [string]
because $x
only has meaning as a string and the interface is used elsewhere.
- How can I make
$x
come out as$null
when it is passed$null
? - Is there some other way I can tell that
$x
was passed$null
not[string]::Empty
from insidef
?
Update 1
What I am trying to do works for other types. Here is the same concept for [int]
:
function f {
param(
[System.Nullable[int]]$x
)
return $x
}
$r = f -x $null
In that case $r
is indeed $null
. $x
can be either $null
or [int]
but nothing else. It seems strange to me to have to allow any object just so I can pass a $null
or [int]
.
[System.Nullable[string]]
produces an error that boils down to [System.Nullable[T]]
requires that [T]
is a value type. [string]
is a reference type, so that doesn't work.
Update 2
It seems to be possible to pass $null
without causing conversion to a parameter of any type except [string]
. I've tested the following:
function f { param([System.Nullable[int]]$x) $x }
function f { param([System.Nullable[System.DayOfWeek]]$x) $x }
function f { param([hashtable]$x) $x }
function f { param([array]$x) $x }
function f { param([System.Collections.Generic.Dictionary[string,int]]$x) $x }
function f { param([System.Collections.ArrayList]$x) $x }
function f { param([System.Collections.BitArray]$x) $x }
function f { param([System.Collections.SortedList]$x) $x }
function f { param([System.Collections.Queue]$x) $x }
function f { param([System.Collections.Stack]$x) $x }
Passing $null
to any of these functions outputs $null. The only parameter type I haven't found a way to which to pass $null
without conversion is [string]
.
Update 3
PowerShell's behavior in this regard is also inconsistent with C#. The corresponding function in C# is as follows:
public string f(string x)
{
return x;
}
Calling f(null)
returns null
.
Update 4
Apparently [NullString]::Value
was intended to address this problem. I seems to work to pass null
to string
parameters in C# APIs. However, [NullString]::Value
gets converted to [string]::empty
in PowerShell the same as $null
. Consider the following code:
function f {
param (
[AllowNull()]
[string]
$x
)
return $x
}
$r = f -x ([NullString]::Value)
$r.GetType().Name
Executing that code outputs String
. $r
is [string]::Empty
despite that [NullString]::Value
was passed to $x
.
Update 5
The PowerShell team has indicated that this was by design:
This is by design and ... changing the behavior would be a massive breaking change.
That thread involved an interesting discussion about the reasoning behind it. I suspect that some of ramifications of this behavior were not understood when the decision was made as the behavior directly contravenes PowerShell cmdlet "Strongly Encouraged Design Guideline" SD03 which reads in part as follows:
If your parameter needs to differentiate between 3 values: $true, $false and “unspecified”, then define a parameter of type Nullable. The need for a 3rd, "unspecified" value typically occurs when the cmdlet can modify a Boolean property of an object. In this case "unspecified" means to not change the current value of the property.