如何在 PowerShell 中将“命名”参数定义为 [ref](这次是真的)

Bre*_*ett 4 powershell

我已经看到了这个,但是两个答案都没有真正回答在函数调用中使用命名参数的问题

这是针对 Powershell 7 的。没有工作流程。这次真的是命名参数了!这里的标准文档也没有涵盖。开始认为这是不可能的。

这是可行的,但它需要带有位置参数的括号,而不是命名参数

Function MyFunction ([ref][string]$MyRefParam) {
    $MyRefParam.Value = "newValue";
}
$myLocal = "oldValue"
Write-Host $myLocal  # Outputs: oldValue
MyFunction ([ref]$myLocal);
Write-Host $myLocal # Outputs: newValue
Run Code Online (Sandbox Code Playgroud)

当然,我们都知道调用 Powershell 函数的最佳方式是使用命名参数MyFunction -Arg1 23而不是位置参数MyFunction 23MyFunction(23)。这些不会通过我们的 Pull 请求!

但这不起作用

Function MyFunction ([ref][string]$MyRefParam) {
    $MyRefParam.Value = "newValue";
}
$myLocal = "oldValue"
Write-Host $myLocal  # Outputs: oldValue
MyFunction -MyRefParam ([ref]$myLocal) # Outputs Cannot process argument transformation on parameter 'MyRefParam'. Reference type is expected in argument.
Write-Host $myLocal # Outputs: oldValue
Run Code Online (Sandbox Code Playgroud)

是否有另一种方法可以在此语法中提供 ref 类型?到目前为止,我已经在参数定义和调用中尝试了 [ref] 和 [ref][string] 的组合 - 我无法得到任何东西让 Powershell 看到我确实传递了 Ref

谢谢你的帮助!

mkl*_*nt0 7

在参数声明中使用类型[ref]约束,即删除附加[string]类型约束(它不会执行任何操作,甚至可以说不应该被允许 - 请参阅底部部分):

Function MyFunction ([ref] $MyRefParam) {
    $MyRefParam.Value = "newValue"
}

$myLocal = 'oldVaue'
MyFunction -MyRefParam ([ref] $myLocal)
$myLocal # -> 'newvalue'
Run Code Online (Sandbox Code Playgroud)

您不能键入实例[ref][ref]不是修改参数声明的关键字ref(如 C# 中的那样),它本身就是一种类型System.Management.Automation.PSReference并且它的值保存属性.Value属于 类型object,即它可以保存任何对象的类型。

结果:

  • 当通过 传递值时,您无法强制执行特定的数据类型[ref][1]

  • 相反,您可以自由地将任何类型的值分配给接收到的实例.Value的属性[ref]

退一步说

  • [ref]主要用于支持使用ref/参数调用.NET APIout

  • 它在纯 PowerShell 代码中的使用是不寻常的,最好避免,尤其是由于尴尬的调用语法。


也就是说,位置参数绑定命名参数绑定之间的双类型约束的行为差异确实令人好奇- 请参阅评论中Mathias R. Jessen 的精彩解释。

然而,真正的问题是,您甚至可以定义涉及 的类型约束(本身不常见)[ref],因为似乎有一个有意的检查来防止这种情况发生,但它并没有出现在参数声明中。

但是,您可以按如下方式使其显示(直接在命令行运行):

# ERROR, because [ref] cannot be combined with other type constraints.
PS> [ref] [string] $foo = 'bar'

Cannot use [ref] with other types in a type constraint
Run Code Online (Sandbox Code Playgroud)

GitHub 问题 #16146中报告了参数声明中未强制执行相同的检查。


[1] 在幕后,当使用强制转换 ( )传递实际值时,会使用非公共的泛型类型,该类型会使用所强制转换的值的任何类型进行实例化。然而,这个泛型类型的属性仍然是类型化的,允许修改以分配任何类型。[ref]System.Management.Automation.PSReference<T>.Value[object]

  • 虽然违反直觉,但这并不是一个错误,而是一个功能的情况([显式绑定参数参数的类型强制](https://github.com/PowerShell/PowerShell/blob/master/src/System.Management. Automation/engine/ParameterBinderController.cs#L1286)) “侵犯”“[ref]”参数的设施。话虽如此,我从未遇到过任何在 PowerShell 函数中实际需要 `[ref]` 参数的用例:) (3认同)
  • 在这两种情况下传递的参数都是“[PSReference[string]]”类型。当参数通过名称显式绑定时,绑定器总是尝试强制为目标类型,在本例中将“[PSReference[string]]”转换为“[string]”。它不再满足“[ref]”。当参数按位置传递时,绑定器不会尝试转换参数 - 并且由于“[PSReference[string]]”可分配给“[ref]”,因此不会再发生错误。 (3认同)
  • 看看 `$refValue = [ref]""; 跟踪命令 { MyFunction $refValue; MyFunction -MyRefParam $refValue } -Name ParameterBinding,TypeConversion` - 类型转换跟踪器在第一次调用期间永远不会发出窥视声,因为 PowerShell 实际上从未尝试强制隐式绑定选项:) (2认同)