为什么[NullString] :: Value与断点的计算结果不同?

时间:2018-07-11 21:39:21

标签: powershell debugging breakpoints null-string

我已经在PowerShell ISE和VS Code中尝试了此代码,但结果却很奇怪。如果没有断点,则输出为EMPTY,但是如果在与"NULL"的行中有断点,则输出为NULL(如预期)。为什么?

function demo {
    param(
        [string] $value = [NullString]::Value
    )

    if ($null -eq $value) {
        "NULL"
    } elseif ($value -eq '') {
        "EMPTY"
    } else {
        "$value"
    }
}

demo

我现在知道,当您使用类型修饰符[string]作为参数时,PowerShell将始终将非字符串值(例如$ null或[NullString] :: Value)转换为(空)字符串。 很好,我可以接受,但是如果在这种情况下调试是如此怪异,那么很难自己弄清楚。

2 个答案:

答案 0 :(得分:1)

PetSerAl多次在问题评论中提供了关键的指针:

known optimization bug是最可能的原因(从Windows PowerShell v5.1 / PowerShell Core v6.1.0开始),而该错误恰好被掩盖调试器中运行时。

因此,您可以使用链接的错误报告中提到的相同的解决方法:在函数正文中的任意位置调用Remove-Variable(其状态就足够了-该调用实际上不必在运行时进行):

function demo {
    param(
        [string] $value = [NullString]::Value
    )

    # Workaround for optimization bug
    if ($False) { Remove-Variable }

    if ($null -eq $value) {
        "NULL"
    } elseif ($value -eq '') {
        "EMPTY"
    } else {
        "$value"
    }
}

demo

现在,无论调试与否,您始终获得"NULL"作为输出。

但是,最好将[NullString]::Value的使用限制为它的设计用途:将null传递给 .NET方法的string类型的参数 -见下文。


关于为什么要使用[NullString]::Value才能将$null传递给字符串参数/将$null存储在[string]变量中,因为.NET字符串通常可以直接存储null$null):

通过(历史)设计,当您将$null分配给''变量时,PowerShell将[string]转换为$null(空字符串);这是基本原理:

来自https://github.com/PowerShell/PowerShell/issues/4616#issuecomment-323530442

  

设计背后的想法是,在大多数情况下,$PSBoundParameters和空字符串都代表相同的错误情况,并且在极少数情况下区别很重要的情况下,null就足以区分知道是否提供了值。

鉴于even passing $null directly performs conversion to '' when passing arguments to string-typed .NET methods,您无法将[NullString]::Value传递给v2以下的此类方法。
为了解决这个问题,版本3引入了$null,它明确表示希望在字符串上下文中传递$null
(另一种选择-将PowerShell字符串默认为$null并允许直接分配[NullString]::Value-被认为是会破坏太多现有脚本的更改。)

使用null超出了预期的用途-即,将string传递给.NET方法中的[string]参数-会遇到问题,因为PowerShell不会期望{{ 1}}变量在其他情况下包含$null

修复上述优化错误将有助于解决该问题,但可能还会有其他陷阱。

答案 1 :(得分:0)

  

$ null与“”之间的差异

     

空字符串与null不同;您需要专门测试   为了那个原因。 Null是对象的不存在,而字符串是   一个对象,即使它是空的。

     

这是PowerShell中的常见陷阱。无论出于什么原因,它都不会   让您将$ null值分配给字符串变量(或字符串)   .NET类型的参数);它被转换为空字符串。这个   调用处理null和.net的.NET方法时可能会引起一些头痛   空字符串有所不同,这就是为什么它们后来在v3中添加的原因(如果我   请记住正确),[System.Management.Automation.NullString]   类。如果要调用这种方法,请执行以下操作:

     

[SomeClass] :: SomeMethod([nullstring] :: Value)

     

[string] $ camp = $ null

     

将$ Null分配给$ Camp,但是由于[string]部分强制$ camp   如果是字符串类型,将为$ Camp分配值   [String] $ Null

     

[String] $ Null将强制转换$ Null(基本上是   不存在的对象)添加到字符串中,并在PowerShell中导致   空字符串。

     

就PowerShell而言,基本上是正确的。然而,   在.NET Framework中,字符串实际上可以为null,并且有一个   空字符串引用和空字符串之间的区别。   有时,当您查看.NET时,会引起混乱   文档并想知道为什么它似乎无法正常工作   PowerShell。

     

使用[string] :: IsNullOrEmpty($ variable)

     

https://powershell.org/forums/topic/difference-between-null-and/

另请参阅...

  

如何在PowerShell中检查字符串是否为空或为空?   [string] :: IsNullOrEmpty(...)

     

How can I check if a string is null or empty in PowerShell?

*更新*

将代码更改为此...

function demo {
    param(
        [string]$value
    )

    if ([string]::IsNullOrEmpty($value))
    {
        "NULL"
    } elseif ($value -eq '') {
        "EMPTY"
    } else {
        "$value"
    }
}

无论是否进行调试(将断点设置为'NULL'和'EMPTY'),返回的结果在我的系统ISE / VSCode上都是相同的

# Results 

demo
NULL

demo -value ''
NULL

demo -value ' '


demo -value test
test

*修改为显示elseif处理空格*

具有或符合上述条件

 function demo {
    param(
        [string]$value
    )

    if ([string]::IsNullOrEmpty($value))
    {
        "NULL"
    } elseif ([string]::IsNullOrWhiteSpace($value)) {
        "EMPTY or a White Space"
    } else {
        "$value"
    }
}

# Results

demo
NULL
demo -value ''
NULL
demo -value ' '
EMPTY or a White Space
demo -value test
test