Como impedir que um argumento de seqüência de caracteres mude de nulo para vazio quando vinculado a um parâmetro?

Considere o seguinte código:

function f {
    param (
        [AllowNull()]
        [string]
        $x
    )
    return $x
}

$r = f -x $null

$null é convertido para[string]::Empty quando chegar a horareturn é atingido.$null é diferente de[string]::Empty e eu gostaria de preservar essa distinção. Eu também preferiria manter$x como tipo[string] Porque$x só tem significado como uma string e a interface é usada em outro lugar.

Como posso fazer$x sair como$null quando é passado$null?Existe alguma outra maneira de dizer isso$x passou$null não [string]::Empty de dentrof?

Atualização 1

O que estou tentando fazer funciona para outros tipos. Aqui está o mesmo conceito para[int]:

function f { 
    param( 
        [System.Nullable[int]]$x 
    )
    return $x 
}

$r = f -x $null

Nesse caso$r é de fato$null. $x pode ser$null ou[int] mas nada mais. Parece-me estranho ter que permitirqualquer objeto apenas para que eu possa passar um$null ou[int].

[System.Nullable[string]] produz um erro que se resume a[System.Nullable[T]] requer que[T] é um tipo de valor.[string] é um tipo de referência, para que não funcione.

Atualização 2

Parece ser possível passar$null sem causar a conversão para um parâmetro de qualquer tipoexceto [string]. Eu testei o seguinte:

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 }

Passagem$null para qualquer uma dessas funções gera $ null. osó tipo de parâmetro Eu não encontrei uma maneira de passar$null sem conversão é[string].

Atualização 3

O comportamento do PowerShell nesse sentido também é inconsistente com o C #. A função correspondente em C # é a seguinte:

public string f(string x)
{
    return x;
}

Chamandof(null) retornanull.

Atualização 4

Pelo visto[NullString]::Value foi planejado para resolver esse problema. Eu pareço trabalhar para passarnull parastring parâmetros em APIs C #. Contudo,[NullString]::Value é convertido em[string]::empty no PowerShell, o mesmo que$null. Considere o seguinte código:

function f {
    param (
        [AllowNull()]
        [string]
        $x
    )
    return $x
}

$r = f -x ([NullString]::Value)
$r.GetType().Name

Executando que o código geraString. $r é[string]::Empty Apesar disso[NullString]::Value foi passado para$x.

Atualização 5

A equipe do PowerShell indicou que isso ocorreu por design:

Isso ocorre por design e ... mudar o comportamento seria uma grande mudança de quebra.

Esse tópico envolveu uma discussão interessante sobre o raciocínio por trás dele. Suspeito que algumas ramificações desse comportamento não tenham sido entendidas quando a decisão foi tomada, pois o comportamento contraria diretamenteCmdlet do PowerShell "Diretriz de design fortemente incentivado" SD03 que lê em parte da seguinte maneira:

Se o seu parâmetro precisar diferenciar entre três valores: $ true, $ false e "não especificado", defina um parâmetro do tipo Nullable. A necessidade de um terceiro valor "não especificado" geralmente ocorre quando o cmdlet pode modificar uma propriedade booleana de um objeto. Nesse caso, "não especificado" significa não alterar o valor atual da propriedade.

questionAnswers(3)

yourAnswerToTheQuestion