所以,我尝试查找这个问题的答案,发现普遍可用的答案是 PowerShell 按值传递参数。这些普遍接受的解决方案都发布了示例代码来证明他们的断言,类似于以下内容:
Function add1 ($parameter)
{
Write-Host " In Function: `$parameter = $parameter"
Write-Host " In Function: `$parameter += 1"
$parameter += 1
Write-Host " In Function: `$parameter = $parameter"
}
cls
$a = 1
Write-Host "Before function: `$a = $a"
add1 $a
Write-Host " After function: `$a = $a"
这给出了结果:
Before function: Run Command: $a = 1
In Function: $parameter: 1
In Function: Run Command: $parameter += 1
In Function: $parameter: 2
After function: $a: 1
从而证明参数是按值传递的,对吗?好吧,我花了很长时间来对我正在编写的函数进行故障排除。该函数向我传递给该函数的 PSCustomObject 添加了几个额外的 NoteProperty 项,并且我的程序会抛出各种错误,指出 NoteProperty 已经存在,即使我没有修改父作用域中的原始对象,只有函数内部。
因此,我设置了上述代码的一个版本来使用 [PSCustomObject] 类型的参数进行测试,如下所示:
Function F1($Obj)
{
'Function F1: Run command: $Obj.FirstValue = 11'
$Obj.FirstValue = 11
" `$Obj.Name: $($StartObject.Name)"
" `$Obj.FirstValue: $($StartObject.FirstValue)"
" `$Obj.SecondValue: $($StartObject.SecondValue)"
}
Function F2($Obj)
{
'Function F2: Run command: $Obj | Add-Member -MemberType NoteProperty -Name SecondValue -Value 33'
$obj | Add-Member -MemberType NoteProperty -Name SecondValue -Value 33
" `$Obj.Name: $($StartObject.Name)"
" `$Obj.FirstValue: $($StartObject.FirstValue)"
" `$Obj.SecondValue: $($StartObject.SecondValue)"
}
cls
Remove-Variable StartObject
"Main script: Run command: `$StartObject = [PSCustomObject]@{Name='Original';FirstValue=22}"
$StartObject = [PSCustomObject]@{Name='Original';FirstValue=22}
" `$StartObject.Name: $($StartObject.Name)"
" `$StartObject.FirstValue: $($StartObject.FirstValue)"
" `$StartObject.SecondValue: $($StartObject.SecondValue)"
'Run command: F1 $StartObject'
" "
F1 $StartObject
" "
"Main script: `$StartObject.Name: $($StartObject.Name)"
" `$StartObject.FirstValue: $($StartObject.FirstValue)"
" `$StartObject.SecondValue: $($StartObject.SecondValue)"
"Run command: F2 $StartObject"
" "
F2 $StartObject
" "
"Main script: `$StartObject.Name = $($StartObject.Name)"
" `$StartObject.FirstValue = $($StartObject.FirstValue)"
" `$StartObject.SecondValue = $($StartObject.SecondValue)"
这段凌乱的编程产生以下输出:
Main script: Run command: $StartObject = [PSCustomObject]@{Name='Original';FirstValue=22}
$StartObject.Name: Original
$StartObject.FirstValue: 22
$StartObject.SecondValue:
Run command: F1 $StartObject
Function F1: Run command: $Obj.FirstValue = 11
$Obj.Name: Original
$Obj.FirstValue: 11
$Obj.SecondValue:
Main script: $StartObject.Name: Original
$StartObject.FirstValue: 11
$StartObject.SecondValue:
Run command: F2 @{Name=Original; FirstValue=11}
Function F2: Run command: $Obj | Add-Member -MemberType NoteProperty -Name SecondValue -Value 33
$Obj.Name: Original
$Obj.FirstValue: 11
$Obj.SecondValue: 33
Main script: $StartObject.Name = Original
$StartObject.FirstValue = 11
$StartObject.SecondValue = 33
这些结果清楚地表明,当使用 [PSCustomObject] 参数时,函数内的任何修改都发生在传递的对象上,因此通过引用传递。无论将我的参数定义为 [PSCustomObject]$Obj 还是不输入它们,都会发生这种行为。这本身并不是一个大问题,但问题是我无法在我浏览的任何文档中找到这个小信息。我检查了一些教程站点和 Microsoft 自己关于函数参数的文档,但没有看到这个异常。
所以,我的问题归结为:有没有人找到任何文档来支持我的理论,即虽然大多数参数默认为按值传递,但当涉及对象时,它们是按引用传递的?
我完全愿意相信我在某处遗漏了一些文档,所以请...指出并告诉我我的方式错误! :)
非常感谢
最佳答案
注意:以下 也适用于 到 将一个变量分配给另一个 : $b = $a
...
* 如果 $b
的值是引用类型的实例,则使 $a
引用与 $a
相同的对象,
* 如果后者是值类型的实例,则使 $b
接收 $a
值的独立副本。
[ref]
类型的参数(类似于 C# 中的 ref
参数)。但是,请注意,在 PowerShell 中很少需要此技术。 [pscustomobject]
是 - 即内容是一个对象引用,和被叫方因此可以潜在地修改该对象,凭借看到非常相同的对象的作为来电者。System.ICloneable
接口(interface),则可以通过调用其 .Clone()
方法创建类型实例的副本,但请注意,执行浅克隆还是深克隆取决于实现类型[1];正是出于这个原因,不鼓励使用此接口(interface);在实践中,实现它的类型通常执行浅克隆,特别是数组、数组列表( System.Collections.ArrayList
)和哈希表(但请注意, [ordered]
哈希表( System.Collections.Specialized.OrderedDictionary
)根本没有实现 ICloneable
60714。.psobject.Copy()
类型的实例上调用 [pscustomobject]
以创建浅拷贝。 (不要在任何其他类型的对象上使用此方法,它实际上是一个无操作。)同样,单个 .NET 类型可以实现自定义克隆方法。 [int]
- 或string[2] ,该实例的 独立副本 被传递。
要确定给定变量的值是值类型还是引用类型的实例,请使用以下内容:
1, (Get-Date), (Get-Item /) | # sample values
foreach {
'{0} is of type {1}; is it a value type? {2}' -f $_,
$_.GetType(),
$_.GetType().IsValueType
}
你会看到类似的东西:
1 is of type System.Int32; is it a value type? True
4/30/2020 12:37:01 PM is of type System.DateTime; is it a value type? True
/ is of type System.IO.DirectoryInfo; is it a value type? False
如果您查找给定 .NET 类型的文档,例如
System.DateTime
,值类型的继承信息将从 Object -> ValueType
开始;在 C# 术语中,值类型是 struct
或 enum
,而引用类型是 class
。术语和概念:
这里有 两个不相关的概念 在这里起作用,而且它们都使用术语 (by-)value 和 (by-)reference 的事实可能会令人困惑:
[1] 浅克隆意味着作为引用类型实例的属性值按原样复制 - 作为引用 - 这意味着克隆的属性值再次引用与原始对象完全相同的对象。深度克隆意味着这些属性值被递归地克隆。深度克隆成本高昂,而且并非总是可行。
[2] 字符串 (
[string]
) 在技术上也是引用类型的实例,但作为一个异常(exception),它被视为值类型;有关此异常背后的基本原理,请参阅 this answer。[3] 另一种思考方式:传递指向变量存储其值的位置的引用(指针)。这允许被调用者不仅可以访问变量的值,还可以分配(新)值。
关于function - PowerShell 函数参数 - 按引用还是按值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60102320/