Arraylist 是否在 PowerShell 中通过引用传递给函数 [英] Is Arraylist passed to functions by reference in PowerShell

查看:23
本文介绍了Arraylist 是否在 PowerShell 中通过引用传递给函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天发现当我从函数内的数组列表中删除一个值时,我传递给函数的数组列表会发生变化.下面的代码似乎暗示传递是通过引用发生的.为什么会这样?这是设计使然还是某种错误?(我在 Win 8.1 上使用 v4)

I found out today that an arraylist I passed to a function gets changed when I remove a value from the arraylist within the function. The code below seems to imply that passing is happening by reference. Why would that be? Is this by design or some kind of bug? (I am using v4 on Win 8.1)

function myfunction {
    param (
        [System.Collections.ArrayList]$local
    )
        "`$local: " + $local.count
        "removing 1 from `$local"
        $local.RemoveAt(0)     
        "`$local:" + $local.count       
}

[System.Collections.ArrayList]$names=(Get-Content c:\temp\names.txt)

"`$names: " + $names.count
 myfunction -local $names      
"`$names: " + $names.count

结果:

$names: 16
$local: 16
removing 1 from $local
$local:15
$names: 15

推荐答案

mjolinor 的有用回答 提供关键指针:要使函数对输入 ArrayList 的副本进行操作,必须通过 .Clone 克隆() 首先.

mjolinor's helpful answer provides the crucial pointer: To have the function operate on a copy of the input ArrayList, it must be cloned via .Clone() first.

遗憾的是,此处提供的为什么需要这样做的解释不正确:[1]

Unfortunately, the explanation offered there for why this is required is not correct:[1]

没有特定于 PowerShell 的变量行为起作用;行为是 .NET 框架本身的基础,它是 PowerShell 的基础:

No PowerShell-specific variable behavior comes into play; the behavior is fundamental to the .NET framework itself, which underlies PowerShell:

变量技术上按值传递(默认情况下[2]),但是意味着什么em> 取决于变量值的类型:

Variables are technically passed by value (by default[2]), but what that means depends on the variable value's type:

  • 对于值类型,对于直接包含数据的变量,制作实际数据副本.
  • 对于引用类型,对于变量仅包含对数据的引用,制作引用的副本,从而有效 通过引用传递.
  • For value types, for which variables contain the data directly, a copy of the actual data is made.
  • For reference types, for which variables only contain a reference to the data, a copy of the reference is made, resulting in effective by-reference passing.

因此,在手头的情况下,因为 [System.Collections.ArrayList]reference 类型(用 验证 - 不是 [System.Collections.Collections.ArrayList].IsValueType),参数 $local 设计为指向与调用范围内的变量 $names 完全相同的 ArrayList 实例.

Therefore, in the case at hand, because [System.Collections.ArrayList] is a reference type (verify with -not [System.Collections.ArrayList].IsValueType), parameter $local by design points to the very same ArrayList instance as variable $names in the calling scope.

不幸的是,PowerShell 可以通过某些操作在幕后克隆对象来掩盖正在发生的事情:

Unfortunately, PowerShell can obscure what's happening by cloning objects behind the scenes with certain operations:

  • 使用 += 附加到数组 ([System.Object[]]):

 $a = 1, 2, 3  # creates an instance of reference type [Object[]]
 $b = $a       # $b and $a now point to the SAME array
 $a += 4       # creates a NEW instance; $a now points to a DIFFERENT array.

  • 使用 += 附加到 [System.Collections.ArrayList] 实例:

    • 数组([System.Object[])的情况下,必须创建一个新实例 - 因为数组根据固定大小的定义 - PowerShell 不幸的是在使用时悄悄地将 [System.Collections.ArrayList] 实例转换为 array+= 因此显然也创建了一个新对象,即使 [System.Collections.ArrayList] 可以增长,即使用 .Add() 方法.

    • While in the case of an array ([System.Object[]) a new instance must be created - because arrays are by definition of fixed size - PowerShell unfortunately quietly converts a [System.Collections.ArrayList] instance to an array when using += and therefore obviously also creates a new object, even though [System.Collections.ArrayList] can be grown, namely with the .Add() method.

    $al = [Collections.ArrayList] @(1, 2, 3)  # creates an ArrayList
    $b = $al       # $b and $al now point to the SAME ArrayList
    $al += 4       # !! creates a NEW object of type [Object[]]
    # By contrast, this would NOT happen with: $al.Add(4)
    

  • 解构数组:

     $a = 1, 2, 3     # creates an instance of reference type [Object[]]
     $first, $a = $a  # creates a NEW instance
    

    [1] mjolinor 的误解是围绕从父(祖先)范围继承/隐藏变量:参数声明隐式本地变量声明.也就是说,在输入 testlocal()$local 已经是一个包含作为参数传递的任何内容的局部变量 - 它永远不会看到同名的祖先变量.下面的代码片段演示了这一点: function foo([string] $local) { "`$local inside foo: $local" };$local = '嗨';"`$local 在调用范围内:$local";富;foo 'bar' - foo() 永远不会看到 $local 的调用范围的定义.

    [1] mjolinor's misconception is around inheriting / shadowing of variables from the parent (ancestral) scope: A parameter declaration is implicitly a local variable declaration. That is, on entering testlocal() $local is already a local variable containing whatever was passed as the parameter - it never sees an ancestral variable of the same name. The following snippet demonstrates this: function foo([string] $local) { "`$local inside foo: $local" }; $local = 'hi'; "`$local in calling scope: $local"; foo; foo 'bar' - foo() never sees the calling scope's definition of $local.

    [2] 请注意,某些 .NET 语言(例如,C# 中的 ref)甚至 PowerShell 本身([ref])也允许传递 变量通过引用,因此局部参数实际上只是调用作用域变量的别名,但此功能与值/引用类型二分法无关.

    [2] Note that some .NET languages (e.g., ref in C#) and even PowerShell itself ([ref]) also allow passing a variable by reference, so that the local parameter is effectively just an alias for the calling scope's variable, but this feature is unrelated to the value/reference-type dichotomy.

    这篇关于Arraylist 是否在 PowerShell 中通过引用传递给函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆