PowerShell 中的函数重载

发布于 2024-09-27 10:24:24 字数 200 浏览 3 评论 0原文

可以在 PowerShell 中重载函数吗?

我希望我的函数接受字符串、数组或某些开关。

我想要的一个例子:

  • Backup-UsersData singleUser
  • Backup-UsersData @('Alice', 'Bob', 'Joe')
  • 备份用户数据 -all

Can you overload functions in PowerShell?

I want to my function to accept a string, array or some switch.

An example of what I want:

  • Backup-UsersData singleUser
  • Backup-UsersData @('Alice', 'Bob',
    'Joe')
  • Backup-UsersData -all

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

梦断已成空 2024-10-04 10:24:24

在 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

In PowerShell functions are not overloaded. The last definition overrides the previous in the same scope or hides the previous in a parent scope. Thus, you should create a single function and provide a way to distinguish its call mode by arguments.

In V2 you may use an advanced function, see help about_Functions_Advanced_Parameters and avoid some manual coding on resolving parameter set ambiguities:

# 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

Note that this mechanism is sometimes strange. For example in the first test we have to specify parameter name -user explicitly. Otherwise:

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

In many cases standard, not advanced, function with mixed parameters will do:

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

But in this case you should resolve (or accept and ignore) ambiguities, e.g. to decide what to do if, say:

Backup-UsersData -user 'John' -array 1, 2 -all
老街孤人 2024-10-04 10:24:24

这是罗马答案的一个变体,我认为它更灵活一些:

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

Here is a variant of Roman's answer that I think is a little more flexible:

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"
        }
    }
}
半暖夏伤 2024-10-04 10:24:24

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

-OR-< /em>


[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 中??? ;-)

希望有帮助...

1) Build a class...

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

1+) Use STATIC METHODS if you prefer to call them without instantiation...

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

2) Call the methods in class or object... overload works OK

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

-OR-


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

3)
If (like me)
you want to have "Overloaded Functions" placed in a libraries...
so your users can use them transparently...
from code or from Interactive Command Line (REPL)...

the closest I could came to
"Overloading functions in Powershell"
was something like this:

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

Maybe in PS-Core v8??? ;-)

Hope it helps...

中性美 2024-10-04 10:24:24

如果您使用 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

If you use PSObject instead of Object to define your parameter type, it should work.
For example, The function Get-Control, know's how to overload based on type string or template and can be called using the positional value:

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

To make the overload work, use PSObject as follows:

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
生活了然无味 2024-10-04 10:24:24

已经发布了一些很好的答案,但我想我会分享另一种方法;虽然从技术上讲,此方法不是函数重载,但它确实提供了类似的功能,这可能就足够了,具体取决于您的要求。

这个想法是使用一个只有 1 个 [HashTable] 类型参数的函数。您需要传递给函数的所有参数都将通过这个单个哈希表参数传递。下面的代码应该很容易看出它是如何工作的。

Function OverLoadedFunction
{
 Param
 (
  [HashTable] $Parameters
 )

 # Default parameter values if desired.
 [String] $Server = 'Default Server'
 [Int]    $Port   = 22

 ForEach ($Parameter In $Parameters.Keys)
 {
  Switch ($Parameter)
  {
   'Server' {$Server = $Parameters.$Parameter.Trim(); Break} 
   'Port'   {$Port   = $Parameters.$Parameter       ; Break}
   Default  {Write-Host 'Not a valid parameter'}
  }
 }
  Write-Host $Server on port $Port
}

Cls

OverLoadedFunction
OverLoadedFunction @{server='new server'}

There are some good answers already posted but I thought I would share another way of doing this; while technically this method is not Function Overloading, it does provide a similar functionality which might be sufficient, depending on your requirements.

The idea is to use a function with only 1 parameter of type [HashTable]. All the parameters that you need to pass to your function will be passed through this single hash table parameter. The code below should be easy enough to see how it works.

Function OverLoadedFunction
{
 Param
 (
  [HashTable] $Parameters
 )

 # Default parameter values if desired.
 [String] $Server = 'Default Server'
 [Int]    $Port   = 22

 ForEach ($Parameter In $Parameters.Keys)
 {
  Switch ($Parameter)
  {
   'Server' {$Server = $Parameters.$Parameter.Trim(); Break} 
   'Port'   {$Port   = $Parameters.$Parameter       ; Break}
   Default  {Write-Host 'Not a valid parameter'}
  }
 }
  Write-Host $Server on port $Port
}

Cls

OverLoadedFunction
OverLoadedFunction @{server='new server'}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文