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

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

问题描述

我今天发现,当我从函数内的arraylist中删除一个值时,传递给函数的arraylist发生了变化.下面的代码似乎暗示传递是通过引用发生的.为什么会这样呢?这是设计使然还是某种错误? (我在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] ),但是 含义取决于变量值的 type :

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 类型(用-not [System.Collections.ArrayList].IsValueType验证),因此设计中的参数$local指向完全相同的ArrayList实例.在调用范围内作为变量$names .

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]实例:

  • Using += to append to a [System.Collections.ArrayList] instance:

    • 在使用数组([System.Object[])的情况下,必须创建一个新实例 -因为数组是根据 fixed 大小-不幸的是,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的误解是围绕从父(祖先)范围继承/隐藏变量:参数声明隐式地是 local 变量声明.也就是说,在输入testlocal() $local时,已经是一个局部变量,包含作为参数传递的内容-它永远不会看到同名的祖先变量.下面的代码段演示了这一点:function foo([string] $local) { "`$local inside foo: $local" }; $local = 'hi'; "`$local in calling scope: $local"; foo; 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天全站免登陆