本文介绍了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.

不幸的是,在那里提供的解释为何不正确?不正确:

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

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

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

对变量进行技术按值传递(默认情况下为),但是 含义取决于变量值的 type :

Variables are technically passed by value (by default), 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
    

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

    07-16 05:32
    查看更多