PowerShell 函数可以处理多种输入类型吗?

rov*_*vda 9 powershell function parameter-sets

我正在开发一个比较两个对象的函数,以便检测它们是否相同。但是我希望它也可以与其他类型一起使用,例如字符串或整数。

C++ 允许您声明具有相同名称的不同函数,以不同的方式处理具有不同输入类型的函数调用。我知道参数集的存在,但据我所知,用户必须指定他正在使用哪个参数集。

我正在尝试做这样的事情

function Compare-Objects{
    Param(
        [Parameter(Mandatory=$true,
        Position=0,
        ParameterSetName = "Hashtables")]
        [ValidateNotNullOrEmpty()] 
        [Hashtable]$Item1Hash,

        [Parameter(Mandatory=$true,
        Position=0,
        ParameterSetName = "Integers")]
        [ValidateNotNullOrEmpty()] 
        [int]$Item1int,
        
        [Parameter(Mandatory=$true,
        Position=1,
        ParameterSetName = "Hashtables")]
        [ValidateNotNullOrEmpty()]
        [Hashtable]$Item2Hash,
        
        [Parameter(Mandatory=$true,
        Position=1,
        ParameterSetName = "Integers")]
        [ValidateNotNullOrEmpty()]
        [Hashtable]$Item2Int
    )
    if($PSCmdlet.ParameterSetNamePositionv -match "Integers"){ Return ($Item1Int -eq $Item2Int)}
    else{
    #do some other stuff with $Item1Hash and $Item2Hash
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我也可以将变量命名为相同,则额外加分(因此$Item1Hash$Item1Int成为$Item1分配了适当类型的变量)

mkl*_*nt0 12

正如Jeff Zeitlin在他的评论中所说:

用户不必显式指定参数集 - PowerShell从调用时传递的参数的特定组合(或不存在)推断适用的参数集。

推断基于参数数据类型,参数是否按位置传递(前面不加参数名称)以及哪些参数被标记为强制,以及生效的参数集的名称反映在(高级)脚本$PSCmdlet.ParameterSetName内部/调用的函数

这种推断适用参数集的能力类似于类 C 语言中的自动方法重载解析。


虽然任何给定参数都可以参与多个参数集(实际上默认情况下是所有参数集的一部分),但您从根本上不能声明具有相同名称不同数据类型的参数

如果您想要这样的“多态”参数,您必须实现自己的逻辑,它不依赖于参数集:

function Compare-Objects {

  [CmdletBinding(PositionalBinding=$false)]
  Param(
      
      [Parameter(Mandatory, Position=0)]
      [ValidateNotNullOrEmpty()] 
      # Define as [object] to initially accept any value; specific types
      # are later enforced inside the function body.
      [object] $Item1 
      ,
      [Parameter(Mandatory, Position=1)]
      [ValidateNotNullOrEmpty()] 
      [object] $Item2
  )

  # Ensure that a supported type was passed.
  if ($Item1.GetType() -notin [int], [hashtable]) { Throw "Unsupported argument type." }

  # Ensure that both arguments have the same type.
  if ($Item1.GetType() -ne $Item2.GetType()) { Throw "Inconsistent argument types." }
  
  if ($Item1 -is [int]) {
    "[int] arguments given."
  }
  else {
    "[hashtable] arguments given."
  }

}
Run Code Online (Sandbox Code Playgroud)

注意:如果单独检查参数参数的类型就足够了,您可以使用属性来修饰参数,如本答案[ValidateScript()]的底部部分所示。


但是,如果不需要使用相同的参数名称,并且您满足于使用不同数据类型的位置调用,则参数集会有所帮助,如以下简化示例所示:

function Foo {
  [CmdletBinding()]
  param(
    [Parameter(ParameterSetName='int', Position=0)]
    [int] $ItemInt
    ,
    [Parameter(ParameterSetName='hash', Position=0)]
    [hashtable] $ItemHash
  )
  "Parameter set chosen: $($PSCmdlet.ParameterSetName)"
 } 

# Call the function first with an [int], then with a [hashtable], positionally.
10, @{ foo = 1 } | ForEach-Object { Foo $_ }
Run Code Online (Sandbox Code Playgroud)

上面的结果如下,显示参数数据类型自动选择了适当的参数集:

function Compare-Objects {

  [CmdletBinding(PositionalBinding=$false)]
  Param(
      
      [Parameter(Mandatory, Position=0)]
      [ValidateNotNullOrEmpty()] 
      # Define as [object] to initially accept any value; specific types
      # are later enforced inside the function body.
      [object] $Item1 
      ,
      [Parameter(Mandatory, Position=1)]
      [ValidateNotNullOrEmpty()] 
      [object] $Item2
  )

  # Ensure that a supported type was passed.
  if ($Item1.GetType() -notin [int], [hashtable]) { Throw "Unsupported argument type." }

  # Ensure that both arguments have the same type.
  if ($Item1.GetType() -ne $Item2.GetType()) { Throw "Inconsistent argument types." }
  
  if ($Item1 -is [int]) {
    "[int] arguments given."
  }
  else {
    "[hashtable] arguments given."
  }

}
Run Code Online (Sandbox Code Playgroud)