Powershell: функция стиля C # перегружается наборами параметров? - PullRequest
2 голосов
/ 18 января 2012

В 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 такие перегрузки не возможны; однако некоторая аппроксимация перегрузки функции предлагается через свойство ParameterSetName System.Management.Automation.ParameterAttribute. Это позволяет нам объявлять параметры как члены определенных наборов параметров, что позволяет нам эффективно определять отдельные сигнатуры для наших функций. Упрощенный случай, встречающийся в большинстве примеров ParameterSetName , выглядит примерно так:

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} 
    } 
}

Get-help для этой функции дает следующее:

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, приведенный в исходном примере, подходит под это описание. Возможно, ключом к этому решению является понимание того, что для каждого параметра в блоке параметров можно объявить несколько свойств параметров. Это позволяет нам устанавливать набор параметров для каждой подписи и украшать каждый параметр атрибутом 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?

Спасибо!

Ответы [ 2 ]

5 голосов
/ 18 января 2012

Если вы пытаетесь эмулировать перегрузки функции 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 голос
/ 17 апреля 2012

Две важные вещи, которые следует помнить о наборах параметров, это то, что среда выполнения Windows PowerShell использует только один набор параметров для конкретного ввода, и что каждый набор параметров должен иметь хотя бы один параметр, уникальный для этого набора параметров.

В вашем случае вам нужно указать второй параметр, например -WorkspaceRoot, и он будет работать:

initialize-something -workspacename "test" -WorkspaceRoot "test2"

...