Подтвердить что ты не робот

Перегрузка функций в PowerShell

Можете ли вы перегрузить функции в PowerShell?

Я хочу, чтобы моя функция принимала строку, массив или некоторый переключатель.

Пример того, что я хочу:

  • Backup-UsersData singleUser
  • Backup-UsersData @( "Алиса", "Боб", 'Joe')
  • Backup-UsersData-all
4b9b3361

Ответ 1

В функциях PowerShell не перегружены. Последнее определение переопределяет предыдущее значение в той же области действия или скрывает предыдущее значение в родительской области. Таким образом, вы должны создать одну функцию и предоставить способ отличить ее режим вызова от аргументов.

В V2 вы можете использовать расширенную функцию, см. help about_Functions_Advanced_Parameters и избегать некоторого ручного кодирования при разрешении неоднозначностей набора параметров:

# advanced function with 3 parameter sets
function Backup-UsersData
(
    [Parameter(Position=0, ParameterSetName="user")]
    [string]$user,
    [Parameter(Position=0, ParameterSetName="array")]
    [object[]]$array,
    [Parameter(Position=0, ParameterSetName="all")]
    [switch]$all
)
{
    # use this to get the parameter set name
    $PSCmdlet.ParameterSetName
}

# test
Backup-UsersData -user 'John'
Backup-UsersData 1, 2
Backup-UsersData -all

# OUTPUT:
# user
# array
# all

Обратите внимание, что этот механизм иногда странный. Например, в первом тесте мы должны явно указать имя параметра -user. В противном случае:

Backup-UsersData : Parameter set cannot be resolved using the specified named parameters.
At C:\TEMP\_101015_110059\try2.ps1:21 char:17
+ Backup-UsersData <<<<  'John'
    + CategoryInfo          : InvalidArgument: (:) [Backup-UsersData], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : AmbiguousParameterSet,Backup-UsersData

Во многих случаях стандартная, а не продвинутая функция со смешанными параметрами будет делать:

function Backup-UsersData
(
    [string]$user,
    [object[]]$array,
    [switch]$all
)
{
    if ($user) {'user'}
    elseif ($array) {'array'}
    elseif ($all) {'all'}
    else {'may be'}
}

Backup-UsersData -user 'John'
Backup-UsersData -array 1, 2
Backup-UsersData -all
Backup-UsersData

Но в этом случае вы должны разрешать (или принимать и игнорировать) двусмысленности, например. решить, что делать, если, скажем:

Backup-UsersData -user 'John' -array 1, 2 -all

Ответ 2

Вот вариант римского ответа, который я считаю немного более гибким:

function Backup
{
    [CmdletBinding(DefaultParameterSetName='Users')]
    Param (
        [parameter(mandatory=$true, ParameterSetName='Users', position=0, ValueFromPipeline=$true)][string[]]$User,
        [parameter(mandatory=$true, ParameterSetName='AllUsers')][switch]$All
    )

    Begin
    {
        if ($All) { $User = @('User1', 'User2', 'User3') }
    }

    Process
    {
        foreach ($u in $User)
        {
            echo "Backup $u"
        }
    }
}

Ответ 3

1) Создайте класс...

class c1 { 
    [int]f1( [string]$x ){ return 1 } 
    [int]f1( [int ]$x ){ return 2 }
    }

1+) Используйте СТАТИЧЕСКИЕ МЕТОДЫ, если вы предпочитаете вызывать их без инстанцирования...

class c1 { 
    static [int] f1( [string]$x ){ return 1 } 
    static [int] f1( [int]$x ){ return 2 } 
    }

2) Вызовите методы в классе или объекте... перегрузка работает нормально

$o1 = [c1]::new()
o1.f1( "abc" ) ~> returns 1
o1.f1( 123 )   ~> returns 2

-или-


[c1]::f1( "abc" ) ~> returns 1
[c1]::f1( 123 )   ~> returns 2

3) Если (как я)
вы хотите, чтобы "перегруженные функции" помещались в библиотеки...
так что ваши пользователи могут использовать их прозрачно...
из кода или из интерактивной командной строки (REPL)...

самый близкий, я мог приехать в
"Перегрузка функций в Powershell"
было что-то вроде этого:

function Alert-String() { [c1]::f1( "abc" ) }
function Alert-Strings(){ [c1]::f1( 123 ) }
function Alert-Stringn(){ [c1]::f1( 123 ) }

Может в PS-Core v8??? ;-)

Надеюсь, это поможет...

Ответ 4

Если вы используете PSObject вместо Object для определения типа вашего параметра, он должен работать. Например, функция Get-Control знает, как перегрузить на основе типа строки или шаблона и может быть вызвана с использованием позиционного значения:

    Get-Control "A-Name-Of-A-Control"
    Get-Control $template

Чтобы перегрузка работала, используйте PSObject следующим образом:

Function Get-Control {
    Param(
        [Parameter(Mandatory=$False,ParameterSetName="ByTemplate",Position=0)]
        [PSObject]
        $Template,

        [Parameter(Mandatory=$False,ParameterSetName="ByName",Position=0)]        
        [String]
        $Name,

        [Parameter(Mandatory=$False)] 
        [Switch]
        $List
      ) 
   ... # remaining code removed for brevity