我假设枚举参数在默认情况下只会采用一个参数,并且在尝试传递两个或更多参数时会抛出异常。
enum Test {one; two; three}
function Test-Enum {[CmdletBinding()] param (
[Test]$number
) $number}
Test-Enum -number one
Test-Enum -number two
Test-Enum -number three
Test-Enum -number one, two # outputs two
Test-Enum -number two, one # outputs two
Test-Enum -number one, three # outputs three
test-Enum -number three, one # outputs three
Test-Enum -number two, three # Cannot convert value error
Test-Enum -number three, two # Cannot convert value error
我在这里遗漏了一些明显的东西,但我无法弄清楚。如何防止使用多个参数调用 Test-Enum?
PS F:\> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.19041.2673
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.19041.2673
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
tl;博士
至少到 PowerShell 7.3.4(截至撰写本文时为当前版本),PowerShell 的参数绑定器处理
[enum]
的派生类型,这些派生类型 not 具有 [Flags]
属性(这使它们成为 bit 字段 其值可以 combined) 就像它们一样。
这使得它总是接受多个值,这不适合non-
[Flags]
枚举类型。
不幸的是,PowerShell 参数绑定器允许您将 多个 值传递给一个
[enum]
类型的参数 ,即使特定类型是是有帮助和适当的)。
如果给定多个值,它们将进行位或,如果结果数字不对应于定义的值,则会发生错误。 您可以从 strings
进行转换以获得等效的行为以了解参数绑定器的作用(您的枚举值的数值隐式为 [Flags]
for
0
one
for 1
和
two
for
2
):
three
虽然此行为对于基于
# -> Same as: [Test] (0 -bor 1) -> two
[Test] 'one, two'
# -> Same as [Test] (1 -bor 2), which FAILS, because 1 -bor 2 is 3,
# and 3 isn't a defined value.
[Test] 'two, three'
的枚举类型是适当且有帮助的,但对于那些不是的枚举类型,它是not
。
Windows PowerShell 的解决方法:
解决方法很麻烦: 将您的参数键入
[Flags]
,这会自动阻止传递
多个使用
[string]
属性来验证传递的字符串是枚举中的值的名称[ValidateScript({ … })]
为了也支持制表符完成,添加一个
[Test]
属性:
[ArgumentCompleter()]
enum Test { one; two; three }
function Test-Enum {[CmdletBinding()] param (
[ValidateScript({
if ($_ -as [Test] -ne $null) { return $true }
throw "$_ is not a valid value. Try one of: $([enum]::GetNames([Test]))"
})]
[ArgumentCompleter({
param($unused1, $unused2, $wordToComplete)
[enum]::GetNames([Test]) -like "$wordToComplete*"
})]
[string] $number
)
$enumVal = [Test] $number
$enumVal
}
派生类型不是必须的,您可以使用
[enum]
作为字符串。 但是,这不会在稍后使用参数值时为您提供类型安全。
:
使用辅助。实现[ValidateSet()]
接口接口的类,您也可以将其与
System.Management.Automation.IValidateSetValuesGenerator
一起使用,并且在其中您可以使用[ValidateSet()]
生成有效名称:
[enum]::GetNames([Test])