Powershell 传递复杂对象 按值,而不是按引用

Powershell pass complex object By Value, not By Reference

提问人:Gordon 提问时间:2/19/2021 最后编辑:Gordon 更新时间:2/19/2021 访问量:453

问:

我正在尝试在一个有序的字典中处理一些数据,然后将其添加到另一个有序的字典中,我可以通过重新初始化我的临时字典来做到这一点,就像这样......

$collection = [Collections.Specialized.OrderedDictionary]::new()

foreach ($id in 1..5) {
    $tempCollection = [Collections.Specialized.OrderedDictionary]::new()
    foreach ($char in [Char]'a'..[Char]'e') {
        $letter = ([Char]$char).ToString()
        if ($id % 2 -eq 0) {
            $letter = $letter.ToUpper()
        }
        $int = [Int][Char]$letter
        $tempCollection.Add($letter, $int)
    }
    $collection.Add($id, $tempCollection)
}

foreach ($id in $collection.Keys) {
    Write-Host "$id"
    foreach ($key in $collection.$id.Keys) {
        Write-Host "   $key : $($collection.$id.$key)"
    }
}

但是,我觉得重新初始化有点低效/不优雅,我宁愿只是那个临时变量。这导致了这个.......Clear()

$collection = [Collections.Specialized.OrderedDictionary]::new()
$tempCollection = [Collections.Specialized.OrderedDictionary]::new()

foreach ($id in 1..5) {
    foreach ($char in [Char]'a'..[Char]'e') {
        $letter = ([Char]$char).ToString()
        if ($id % 2 -eq 0) {
            $letter = $letter.ToUpper()
        }
        $int = [Int][Char]$letter
        $tempCollection.Add($letter, $int)
    }
    $collection.Add($id, $tempCollection)
    $tempCollection.Clear()
}

foreach ($id in $collection.Keys) {
    Write-Host "$id"
    foreach ($key in $collection.$id.Keys) {
        Write-Host "   $key : $($collection.$id.$key)"
    }
}

问题在于,虽然字符串、int、char 等简单对象是通过值传递的,但所有复杂对象(如字典)都是通过引用传递的。所以我在每次迭代中都传递相同的字典,并且清除了 的最终状态,因此结果是 的 5 个空成员。$collection.Add($id, $tempCollection)$tempCollection$collection

我知道我可以使用此处概述的通常按值传递的东西强制为按引用。并且只是一个加速器。因此,我需要的是一种按值强制参数的方法,但既不起作用也不起作用,并且搜索似乎也没有返回任何有用的东西。上面链接的 PSReference doco 说[Ref][Ref]System.Management.Automation.PSReference[Val][ByVal]System.Management.Automation.PSValue

此类用于描述这两种类型的引用:

A. 对值的引用:_value将保存被引用的值。

b. 对变量的引用:_value将持有 PSVariable 实例。

这让我觉得我可以以某种方式达到价值,但对于我的生活,我无法摸索如何。我是走在正确的轨道上,只是遗漏了一些东西,还是我完全误解了这个文档?

克隆似乎也是一个潜在的解决方案,即 ,但有序词典没有实现 ICloneable。 也不是一个选项,因为它不一定保持元素的顺序。从那以后也没有$collection.Add($id, $tempCollection.Clone()).CopyTo().AsReadOnly()

AsReadOnly 方法在当前 OrderedDictionary 集合。对 OrderedDictionary 所做的更改 集合反映在只读副本中。OrderedDictionary 的实现方式也不像 PSObject 那样。.copy()

我还尝试制作一个新变量,如下所示......

$newCollection = $tempCollection
$collection.Add($id, $newCollection)
$tempCollection.Clear()

那也行不通。因此,通过引用的复杂对象似乎不仅适用于传递的参数。

似乎我的 Ordered Dictionary 选择/需求几乎是问题的根源,但似乎需要 Ordered Dictionary 的未连接副本不会是不支持的边缘情况。

PowerShell 参数传递 by-value

评论

1赞 Mathias R. Jessen 2/19/2021
如果要存储 5 个不同的词典,则需要创建 5 个不同的词典。
0赞 iRon 2/19/2021
查找短语“”,例如:在 PowerShell 中深度复制字典(哈希表)深度复制 PSObjectDeep Copy
0赞 Gordon 2/19/2021
@iRon 问题在于反序列化不能保持顺序,这就是我首先使用有序字典的全部原因。正如 Mathias 所说,我必须创建多个词典(重新初始化意味着每次都要从技术上创建一个新词典,这样才能工作),但我仍然想知道,为什么不能复制一个词典?我希望产生第二个字典,它以与第一个字典相同的数据开头,但又是独立的,而不是对第一个字典的引用,只不过是一个新的变量名称来访问它。$dictionary1 = $dictionary2
0赞 Gordon 2/19/2021
[Collections.Generic.List]看起来是一样的,所以是有原因的,我相信知道为什么会带来一些更深层次的理解。:)
1赞 Mathias R. Jessen 2/19/2021
好吧,答案可能是“因为无论谁实施,都没有被迫实施”——有些谜团实际上并不那么神秘:-)OrderedDictionaryICloneable

答: 暂无答案