在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属性可以通过一些优雅来完成吗?
谢谢!
答案 0 :(得分:5)
如果您试图模拟C#函数重载,最简单的方法是简单地允许“可选”参数,例如:
function Initialize([int]$version, [string]$workspaceName, [string]workspaceRoot, [switch]Force)
调用者未指定的参数将默认为$ null(开关默认为$ false)。您还可以为参数提供默认值,如下所示:
function Initialize([int]$version, [string]$workspaceName = $(<script here>), [string]workspaceRoot, [switch]Force)
答案 1 :(得分:1)
有关参数集的两个重要事项是,Windows PowerShell运行时仅为特定输入使用一个参数集,并且每个参数集必须至少有一个对该参数集唯一的参数。
在您的情况下,您需要指定第二个参数,例如-WorkspaceRoot
,它将起作用:
initialize-something -workspacename "test" -WorkspaceRoot "test2"