【发布时间】:2012-02-13 11:56:58
【问题描述】:
在 C# 中,函数重载在历史上曾出现过类似以下的情况,其中每个重载都会在更简单的签名之上添加一些参数:
public void Initialize(int version);
public void Initialize(int version, string workspaceName);
public void Initialize(int version, string workspaceName, Path workspaceRoot, bool force);
在 Powershell 中,这些重载是不可能的;但是,通过 System.Management.Automation.ParameterAttribute 的 ParameterSetName 属性提供了一些函数重载的近似值。这允许我们将参数声明为某些参数集的成员,这使我们能够有效地为我们的函数定义单独的签名。大多数ParameterSetName examples 中的简单案例是这样的:
function test-param
{
[CmdletBinding(DefaultParametersetName="p2")]
param(
[Parameter(ParameterSetName="p1",Position=0)]
[String]
$d,
[Parameter(ParameterSetName="p2", Position=0)]
[String]$i
)
switch ($PsCmdlet.ParameterSetName)
{
"p1" { Write-Host ([DateTime]$d); break}
"p2" { Write-Host ([INT]$i); break}
}
}
获取此函数的帮助会产生以下结果:
PS D:\.ws> get-help test-param
test-param [[-i] <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
test-param [[-d] <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
但是,这种基本类型的示例对于参数集的复杂用法并不令人难以置信,因为参数集是完全互斥的。但是如果我们想让一些参数成为所有参数集的成员呢?更有经验的用户可能会建议这是特殊“AllParameterSets”参数集的情况,根据 MSDN,如果未指定参数集,则该参数集是默认值。但是,请考虑以下事项:
PS D:\.ws> function test-param
{
[CmdletBinding(DefaultParametersetName="p2")]
param
(
[Parameter(ParameterSetName="p1",Position=0)]
[String]
$d,
[Parameter(ParameterSetName="p2", Position=0)]
[String]$i,
[Parameter(ParameterSetName="AllParameterSets")]
[String]$x
)
}
PS D:\.ws> get-help test-param
test-param [[-i] <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
test-param [[-d] <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
test-param [-x <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
显然,当“AllParameterSets”被指定为参数集时,它实际上并没有像预期的那样包含在所有参数集中。这可以通过省略声明来看出:
PS D:\.ws> function test-param
{
[CmdletBinding(DefaultParametersetName="p2")]
param
(
[Parameter(ParameterSetName="p1",Position=0)]
[String]
$d,
[Parameter(ParameterSetName="p2", Position=0)]
[String]$i,
[String]$x
)
}
PS D:\.ws> get-help test-param
test-param [[-i] <String>] [-x <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
test-param [[-d] <String>] [-x <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
现在,$x 参数出现在我们所期望的所有函数签名中。
最后,最复杂的情况。如果我们希望一个参数出现在某些而不是所有签名中怎么办?原始示例中给出的 workspaceName 参数符合此描述。也许这个解决方案的一个关键是意识到可以为 param 块中的每个参数声明多个 Parameter 属性。这允许我们为每个签名建立一个参数集,并用它所属的每个集合的 Parameter 属性来装饰每个参数。考虑以下几点:
PS D:\.ws> function Initialize-Something
{
[CmdletBinding()]
param
(
[Parameter(ParameterSetName="version")]
[Parameter(ParameterSetName="workspaceName")]
[Parameter(ParameterSetName="createWorkspace")]
[int] $Version,
[Parameter(ParameterSetName="workspaceName")]
[Parameter(ParameterSetName="createWorkspace")]
[string] $WorkspaceName,
[Parameter(ParameterSetName="createWorkspace")]
[string] $WorkspaceRoot,
[Parameter(ParameterSetName="createWorkspace")]
[switch] $Force
)
}
PS D:\.ws> get-help initialize-something
Initialize-Something [-Version <Int32>] [-WorkspaceName <String>] [-WorkspaceRoot <String>] [-Force] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Initialize-Something [-Version <Int32>] [-WorkspaceName <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Initialize-Something [-Version <Int32>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
PS D:\.ws> initialize-something -workspacename "test"
Initialize-Something : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:21
+ initialize-something <<<< -workspacename "test"
+ CategoryInfo : InvalidArgument: (:) [Initialize-Something], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Initialize-Something
Powershell 声称它无法确定参数集,这很可能是因为 WorkspaceName 出现在多个签名中。作为记录,这也发生在仅指定 -Version 或除最复杂之外的任何签名时。这可以通过 [CmdletBinding(DefaultParameterSetName="version")] 或其他东西得到一定程度的缓解,但这不是一个合适的解决方案。
毕竟,我的问题是:我怎样才能获得我正在寻找的那种签名?我是否需要创建一组过于明确的开关,例如 -VersionMode、-WorkspaceNameMode、-CreateWorkspaceMode 来指定我希望它运行的模式,从本质上否定参数集检测的好处?也许是模式枚举?这可以通过使用 ParameterAttribute 的 Mandatory 和 Position 属性来完成吗?
谢谢!
【问题讨论】:
标签: powershell parameters optional-parameters overloading