当前位置: 首页 > 知识库问答 >
问题:

如何防止字符串参数在绑定到参数时从 null 更改为空?

汪弘毅
2023-03-14

考虑以下代码:

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

$r = f -x $null

$null在到达返回时转换为[string]::Empty$null不同于[string]::Empty,我想保留这种区别。我也更喜欢将$x保留为类型[string],因为$x仅具有字符串的含义,并且接口在其他地方使用。

    < li >当< code>$null被传递时,如何使< code>$x作为< code>$null出现? < li >有没有其他方法可以让我知道< code>$x是从< code>f内部< code>$null而不是< code>[string]::Empty传递的?

更新1

我试图做的对其他类型的人也有效。以下是< code>[int]的相同概念:

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

$r = f -x $null

在这种情况下,$r确实是$null$x可以是$null[int],但没有别的。对我来说,必须允许任何对象才能传递$null[int]似乎很奇怪。

[System.Nullable[string]]产生一个错误,归结为[System.Nullable[T]]要求[T]是值类型。[string]是引用类型,因此不起作用。

更新 2

似乎可以传递$null而不会导致转换为任何类型的参数,除了[string]。我已经测试了以下各项:

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 }

将<code>$null。

更新3

PowerShell在这方面的行为也和C#不一致。C#中相应的函数如下:

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

调用f(null)返回null

更新4

显然,[空字符串]::值旨在解决此问题。我似乎致力于将空值传递给C#API中的字符串参数。但是,[空字符串]::值在 PowerShell 中转换为 [字符串]::空,与$null相同。请考虑以下代码:

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

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

执行该代码输出String$r[string]::Empty,尽管[NullString]::值已传递给$x

更新5

PowerShell团队表示这是有意为之:

这是设计和...改变行为将是一个巨大的突破性变化。

该主题涉及到关于其背后原因的有趣讨论。我怀疑在做出决定时,这种行为的一些后果没有被理解,因为这种行为直接违反了PowerShell cmdlet“强烈鼓励的设计指南”SD03,其部分内容如下:

如果参数需要区分 3 个值:$true、$false和“未指定”,请定义类型为 Nullable 的参数。当 cmdlet 可以修改对象的布尔属性时,通常会出现对第三个“未指定”值的需求。在这种情况下,“未指定”表示不更改属性的当前值。

共有3个答案

萧焱
2023-03-14

默认情况下,[string]将默认值指定为< code>[string]::Empty,因此每当进入函数f时,参数定义都会转换它

[object]$newparamnull -eq $null
[string]$newparamstring -eq [string]::Empty    

b.上一个更改将完成这项工作:

function f {
    param (
        [AllowNull()]
        [object]
        $x)
   if($x -eq $null) {
      write-output "null" 
   }
   elseif($x -eq [string]::empty){
      write-output "empty"
   } 
   else {"other"}
}

测试:

f -x $null
f -x [string]::empty
f -x "aaa"
唐焕
2023-03-14
function f {
    param (
        [AllowNull()]$x
    )
    return $x
}

$r = f -x $null

通过移除< code>[string]并使用< code>[AllowNull()],上面的函数现在将允许您传入一个空对象或空字符串。您可以使用带有if语句的< code>$x.GetType来检查类型,并确定< code>$x是null还是空字符串。

汪安宁
2023-03-14

总结和补充问题、答案和评论中的信息:

tl;dr:

最好不要反对PowerShell的设计,即不允许[string]变量为$null,并将[空字符串]::Value的使用限制为对.NET方法的调用。

>

  • PowerShell将$null转换为"(空字符串),当它被分配给[string]类型的[参数]变量时,参数变量也默认为"

    >

  • 唯一的例外是在PSv5自定义类中使用未初始化的[string]属性,正如alxr9(OP)指出的:类c{[string]$x}$null-eq([c]::new())。x确实产生$True,这意味着属性。x包含$null。然而,这个异常很可能是偶然的,也可能是一个bug,因为当您使用<code>$null从[string]-类型化方法返回$null将输出'

    除此之外,PowerShell的行为与C#字符串变量/参数不同,您可以直接分配/传递null,并且在某些上下文中默认为nullstring是.NET引用类型,此行为适用于所有引用类型
    (由于引用类型实例可以固有地包含null,因此不需要通过System.nullable`1单独的可空包装器,这确实不受支持(仅适用于值类型)

    如问题(更新5)中所述,PowerShell偏离C#的行为是由(设计,它正在改变它不是仅出于向后兼容性的原因的选项。

    [NullString]::Value是在v3中引入的,专门允许将null传递给. NET方法的string参数-虽然在纯PowerShell代码中使用并没有被明确阻止或阻止,但更新4中的意外行为和核心PowerShell团队成员的评论(见下文)表明此类使用不是预期的。

    • 警告:虽然可以在纯PowerShell代码中使用<code>[NullString]::Value从来不是在调用.NET方法的上下文之外;引用PowerShell团队的核心成员的话:

    C#方法的参数是<code>〔null字符串〕:Value</code>的目标场景,我会说这可能是唯一合理的场景。

    • 一种解决方法是将您的(参数)变量键入为[对象]或根本不键入约束它,这相当于相同。此类变量很乐意接受$null,但请注意,您可能必须自己对非$null值进行stringify(转换为[string])(尽管PowerShell会在显式或隐式字符串上下文中自动为您执行此操作)-请参阅下面倒数第二个代码示例。

    尽管有上面的建议,如果您确实需要一个< code>[string]参数变量,您可以通过< code>[NullString]::Value将< code>$null传递给它,就像您问题中的update 4一样,由于PetSerAl的侦查,对于阻止您的代码工作的优化错误,有一个模糊的解决方法:

    function f {
        param (
            [string] $x
        )
        # Workaround; without this, even passing [NullString]::Value 
        # returns '' rather than $null            
        if ($False) { Remove-Variable } 
        return $x
    }
    
    $r = f -x ([NullString]::Value)
    $r.GetType().Name  # now fails, because $r is $null
    

    请注意,当将 [NullString]::Value 赋值到 [字符串] 类型的 [参数] 变量时,它会立即转换为$null(对于参数变量,仅当 bug 得到修复或具有解决方法时)。但是,一旦$null以这种方式成功存储在变量中,它显然可以像这样传递(同样,只有当错误得到修复或解决方法到位时)。

    如果您不想依赖解决方法/等待修复和/或不想让调用者负担必须传递<code>〔NullString〕:Value</code>而不是<code<$null</code>,您可以基于Curios和Jason Schnell的答案,这依赖于使用非类型化(隐式<code>对象</code>-类型化)或显式<code>对象>〔对象</代码>-参数,它可以接受$null如下:

    function f {
        param (
            [AllowNull()] # Explicitly allow passing $null.
                          # Note: Strictly speaking only necessary with [Parameter(Mandatory=$True)]
            $x # Leave the parameter untyped (or use [object]) so as to retain $null as-is
        )
    
        # Convert $x to a type-constrained [string] variable *now*:
        if ($null -eq $x) {
            # Make $x contain $null, despite being [string]-typed
            [string] $x = [NullString]::Value
        } else {
            # Simply convert any other type to a string.
            [string] $x = $x
        }
    
        # $x is now a bona fide [string] variable that can be used
        # as such even in .NET method calls.
    
        return $x
    }
    

    这有点麻烦,但使调用方能够直接传递$null(或任何字符串,或将转换为字符串的任何其他实例的类型)。

    一个轻微的缺点是,这种方法不允许您通过参数的特定类型选择的不同参数集来定义同一位置的位置参数。

    最后,值得一提的是,如果足以检测何时省略了(非强制性)参数,则可以检查$PSBoundParameters

    function f {
        param (
            [string] $x
        )
    
        if ($PSBoundParameters.ContainsKey('x')) { # Was a value passed to parameter -x?
            "-x argument was passed: $x"
        } else {
            "no -x argument passed."
        }
    }
    

    如上所述,这只适用于省略的情况(因此根本不适用于强制参数)。如果您传递< code>$null,则通常的到< code>''的转换开始生效,并且您将无法区分传递< code>$null和< code>''。< br >(但是,如果您添加了上述解决方法/等待错误修复,您可以再次传递< code>[NullString]::Value来有效地传递< code>$null,甚至使用< code>[NullString]::Value作为参数默认值。)

  •  类似资料:
    • 这可能是非常基本的东西,但我很难弄清楚我哪里出错了。 我试图从帖子正文中获取一个字符串,但“jsonString”只显示为null。我还想避免使用模型,但这可能是不可能的。我与PostMan接触到的一段代码是: 也许这是我在postman上做得不正确的地方,但我一直在尝试在body-x-www-form-urlencoded部分的值部分使用“=test”(如在有关此主题的其他问题中看到的),键为j

    • 问题内容: 我有一个动作,可以从用户那里接收一些参数(例如日期)。此操作产生许多不同的报告,因此它具有许多不同的方法。在每种方法之前,我都需要 调整 这些参数(将时间设置为午夜)。该方法在绑定参数之前执行。是否有其他拦截器或其他允许我执行此操作的约定? 问题答案: 使用 如果您使用的是 Convention Plugin,请立即 对其进行操作

    • 如何拥有绑定类型的可选参数

    • 我有应用程序,以自定义字体样式生成报告,如字体家族,颜色,大小和样式(粗体,斜体,下划线)。我使用Windows系统中的所有字体族。

    • 问题内容: 我有一个HTML表单字段,其中包含一些URL字符串作为值。示例值是: 等等 如何仅从这些URL /值中获取参数? 请注意,我没有从浏览器地址栏中获取这些字符串。 问题答案: 您可以使用和。

    • 我有一个HTML表单字段< code > $ _ POST[“url”],值是一些URL字符串。 示例值为: 等等。 如何仅从这些 URL/值中获取参数? 请注意,我不是从浏览器地址栏中获取这些字符串的。