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
$xcome out as$nullwhen it is passed$null? - Is there some other way I can tell that
$xwas passed$nullnot[string]::Emptyfrom 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.