PowerShell函数参数-按引用还是按值?

马修

因此,我尝试查找该问题的答案,发现通常可用的答案是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自己的文档,但是没有看到此异常。

因此,我的问题可以归结为:有没有人找到任何文档来支持我的理论,即尽管大多数参数默认为按值传递,但在涉及对象时它们是通过引用传递的?

我非常愿意相信我在某处错过了一些文档,所以请...指出并向我展示我的方式中的错误!:)

非常感谢

mklement0

注:以下也适用分配一个变量到另一个$b = $a...
*品牌$b引用相同的对象$a不如果$a的值是一个实例引用类型
*品牌$b收到一个独立的副本$a的值,如果后者是值类型的实例

  • 在默认情况下,PowerShell使用按(可变)传递也就是说,传递变量内容,而不是引用变量本身。

    • 如果要按(变量)传递引用则需要付出额外的努力,即,如果要将引用传递给变量本身,则允许被调用方既获取变量的内容,又分配新的内容以最简单的形式,您可以使用[ref]-typed参数(类似于refC#中的参数)。但是,请注意,在PowerShell中很少需要使用此技术。
  • 这是否内容是一份什么样的调用方看到或以相同的对象引用依赖于数据类型的内容

    • 如果内容碰巧是.NET引用类型的实例(按原样),[pscustomobject]则该内容是对象引用因此被调用者可以通过看到与调用者相同的对象来潜在地修改该对象

      • 如果要传递引用类型实例副本(克隆),请注意,没有通用的机制可以创建一个实例
        • 如果类型实例的实例通过调用其方法来实现接口,可以创建它们的副本,但是请注意,执行克隆还是克隆取决于实现类型[1]出于这个原因,不鼓励使用此接口;实际上,实现它的类型通常执行浅层克隆,尤其是数组,数组列表()和哈希表(但请注意,哈希表()根本不实现System.ICloneable.Clone()System.Collections.ArrayList[ordered]System.Collections.Specialized.OrderedDictionaryICloneable
        • 此外,在PowerShell中,您可以调用.psobject.Copy()类型的实例[pscustomobject]来创建浅表副本。(做使用任何其他类型的,在那里它将有效地是一个空操作的对象此方法。)类似地,个别的.NET类型可以实现定制克隆方法。
    • 相反,如果该内容是.NET值类型的实例(例如[int]-)字符串[2]则传递该实例独立副本

    • 这种区别是.NET的基础,而不是特定于PowerShell。例如,这也是在C#中传递参数的方式。

要确定给定变量的值是值类型的实例还是引用类型的实例,请使用类似以下内容的方法:

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#术语来说,值类型是astruct或an enum,而引用类型是a class


术语和概念:

这里有两个不相关的概念,它们都使用术语值)(按引用)可能会引起混淆:

  • 传递(变量)值与传递(变量)参考参数是一个数据持有者(变量)概念

    • 它描述了在传递参数时是传递变量的(按值)还是引用变量本身[3](按引用)。
  • 引用类型与值类型纯粹是一个数据概念

    • 也就是说,出于技术原因,.NET中的任何对象要么是值类型的实例(存储在堆栈上),要么是引用类型的实例(存储在堆上)。前者的实例直接存储在变量中,而后者通过引用存储因此,复制变量(例如,在按值传递参数的情况下)意味着:
      • 任一个:本身复制值类型实例的副本,从而产生独立的数据副本
      • 或:复制引用类型实例引用但是,引用的副本仍然指向同一对象,这就是为什么被调用者甚至可以直接看到通过变量值传递的引用类型实例(通过引用副本的方式)的原因。

[1]克隆表示作为引用类型实例的属性值按原样复制(作为引用),这意味着克隆的属性值再次引用与原始对象相同的对象。深层克隆意味着将递归地克隆此类属性值。深克隆很昂贵,而且并非总是可能的。

[2]字符串([string])从技术上讲也是引用类型的实例,但作为例外,它被视为值类型;有关此异常背后的原因,请参见此答案

[3]另一种思考方式:传递对变量存储其值的位置的引用(指针)。这样,被调用者不仅可以访问变量的值,还可以分配(新)值。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Swift函数是按值还是按引用分配/传递?

从右值引用合格成员函数按值还是按右值引用返回?

C ++函数输入参数按引用还是按指针

在C#中,我应该按值传递参数并返回相同的变量,还是按引用传递?

我应该按值还是按引用传递函数对象?

C ++中的函数重载按值或按引用传递参数

在python中自定义类对象的参数传递:按引用调用还是按值调用求值?

构造函数参数的引用成员按值传递

提供按值和按引用均可用的函数版本

C ++按值传递/按引用函数重载

Python函数调用链表,按值调用/按引用调用

引用函数按值和自动返回

Python 函数按引用、值或对象调用

按值分配还是按引用分配?

Java是按引用还是按值返回

Python-按值还是按引用

.bind(this)是按引用还是按值传递?

为了支持移动语义,函数参数应该由unique_ptr,按值还是按rvalue接受?

传递函数右值引用,当它按值作为参数时

put_money是否按值或引用保留其参数?

按引用/值的参数如何在C#中工作

js中的函数按值或引用复制/传递

C ++获取常量引用中按值返回的函数结果

c ++ lambda:求和函数:使用按值捕获和按引用捕获返回不同的结果

NSInvocation和按引用参数

Ruby是按引用传递还是按值传递?

Golang地图是按值还是按引用查找?

ELM是按引用传递还是按值传递?

python pandas dataframe,是按值传递还是按引用传递