为什么不能将字符串赋值给强类型的布尔变量?

Man*_*ing 5 powershell

假设我尝试将字符串分配给强类型的整数变量:

[int]$bar = '1'
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为PowerShell能够将字符串'1'转换为整数.

现在情况有所不同,如果我尝试使用强类型布尔变量:

[boolean]$foo = 'foo'
Cannot convert value "System.String" to type "System.Boolean". Boolean parameters accept only Boolean values and numbers, such as $True, $False, 1 
or 0.
Run Code Online (Sandbox Code Playgroud)

我发现这令人困惑,因为PowerShell同时允许从字符串显式转换为布尔值:

[boolean]'foo'
True
Run Code Online (Sandbox Code Playgroud)

有谁知道这种看似不一致行为的原因?

Mat*_*sen 4

实用建议:

在大多数情况下,我会主张以下方法,而不是类型化变量:在赋值之前将值转换为目标类型,然后让类型系统推断变量类型:

$foo = [bool]"foo"
$foo = "foo" -as [bool]
$foo = $true -eq "foo"
Run Code Online (Sandbox Code Playgroud)

手头的问题:

(这不是权威答案,只是最佳猜测)

帮助文件中简单提到about_Variables:

变量类型

您可以在变量中存储任何类型的对象,[...]

Windows PowerShell 变量是“松散类型”的,这意味着它们不限于特定类型的对象。[...]

[...关于值推断类型的部分 bla bla bla ...]

您可以使用类型属性和强制转换表示法来确保变量只能包含指定类型的对象或可以转换为该类型的对象。如果您尝试分配其他类型的值,Windows PowerShell 会尝试将该值转换为其类型。如果不能,则赋值语句失败。

要使用强制转换表示法,请在变量名称之前(在赋值语句的左侧)输入类型名称,并将其括在方括号中。

尽管“类型属性”和仅在赋值期间适用的独特约束在文档中的其他地方没有使用,但(至少对我来说)表明这是显式转换的特殊情况。


这意味着什么?

当您在赋值过程中向变量添加显式强制转换符号时,如上所述,PowerShell 会ArgumentTypeConverterAttribute向变量添加 an ,并且 PowerShell 的类型转换魔法会突然被特定于类型的Transform()方法覆盖:

PS C:\> $var = 5
PS C:\> Get-Variable var |fl *


Name        : var
Description :
Value       : 5
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}



PS C:\> [int]$var = 5
PS C:\> Get-Variable var |fl *


Name        : var
Description :
Value       : 5
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {System.Management.Automation.ArgumentTypeConverterAttribute}
Run Code Online (Sandbox Code Playgroud)

如果我们使用布尔类型重复此实验,您可以看到转换ArgumentTypeConverterAttribute比正常转换“魔法”更具限制性:

PS C:\> [bool]$foo = $true
PS C:\> (Get-Variable foo).Attributes[0].Transform($ExecutionContext,"foo")
Exception calling "Transform" with "2" argument(s): "Cannot convert value "System.String" to type "System.Boolean". Boolean parameters
accept only Boolean values and numbers, such as $True, $False, 1 or 0."
At line:1 char:1
+ (Get-Variable foo).Attributes[0].Transform($ExecutionContext,"foo")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentTransformationMetadataException
Run Code Online (Sandbox Code Playgroud)

同样,在这种类型的转换中,布尔参数仅接受布尔值和数字,例如 $True、$False、1 或 0.,而 powershell 本身通常将任何非空、非零或非空值$true隐式解释为转换成[bool]。

换句话说:

转换符号是上下文相关的:

[bool]$SomeVariable = [bool]"bar"
   ^                ^   ^
   |                |   |
   |  during assignment |
This is a type attribute|
         This is a cast notation
Run Code Online (Sandbox Code Playgroud)

尽管它们看起来完全一样