Powershell 为什么不能将字符串指定给强类型布尔变量?

Powershell 为什么不能将字符串指定给强类型布尔变量?,powershell,Powershell,假设我尝试将字符串分配给强类型整数变量: [int]$bar = '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. 这是可行的,因为PowerShell能够将字符串'1'转换为整数 现在

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

[int]$bar = '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.
这是可行的,因为PowerShell能够将字符串
'1'
转换为整数

现在,如果我尝试对强类型布尔变量执行相同操作,情况就不同了:

[int]$bar = '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.
我发现这令人困惑,因为PowerShell同时允许从字符串到布尔值的显式转换:

[boolean]'foo'
True
有人知道这种看似不一致的行为的原因吗?

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

$foo = [bool]"foo"
$foo = "foo" -as [bool]
$foo = $true -eq "foo"

当前的问题是: (这不是权威答案,而是最佳猜测)

关于变量的帮助文件中简要提到:

变量类型

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

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

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

您可以使用类型属性和强制转换符号来确保 变量只能包含指定类型的一个或多个对象 可以转换为该类型的。如果您尝试分配一个值 对于另一种类型,Windows PowerShell尝试将该值转换为 它的类型。如果不能,赋值语句将失败

若要使用强制转换表示法,请在 变量名(位于赋值语句的左侧)

虽然文档中没有使用“类型属性”和仅在赋值过程中应用的独特约束,但(至少对我来说)表明这是显式转换的特例


这意味着什么? 当您在赋值期间向变量添加显式强制转换表示法时,如上所述,PowerShell会向变量添加一个
ArgumentTypeConverterAttribute
,并且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}
如果我们用布尔类型重复这个实验,您可以看到
ArgumentTypeConverterAttribute
转换比普通转换“魔法”限制更大:

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

换言之:

强制转换符号与上下文相关:
即使它们看起来完全一样

如果尝试执行$foo='foo',然后执行[boolean]$foo会发生什么?错误消息完全有效,因为我们知道bools可以是1或0。现在,对于第二个代码段,PS似乎正在返回对字符串长度的检查。对空字符串的强制转换返回
false
,否则每当字符串的长度>=1时,其
true
。原因是“设计就是这样”。另请参见一个类似的问题@SzabolcsPáll这当然有效,因为
[boolean]$foo
也是一个显式转换。我的猜测是,在[boolean]$foo='foo'中,实际转换是由赋值运算符进行的,该运算符不使用tobolean/Parse,而是使用另一个不接受字符串的函数来转换它。任何人都可以证明/反驳它?这是一个很好的解释,说明了当“错误”类型的值分配给强类型变量时会发生什么。与“普通”类型转换魔法相比,这会导致不同的施法行为,这仍然很奇怪。但是这个问题回答得很好。我想“强类型”语法重用了C#/.NET CTS中的转换规则,以避免重新实现自身使用。这也将为来自其他.NET语言的开发人员提供一些一致性