Powershell - 如何使用 $List.convertAll() 或备用 C# 方法克隆列表

Powershell - How-to use $List.convertAll() or alternate C# method to clone a list

假设我有一个列表:

$DeletedUsers = New-Object System.Collections.Generic.List[System.object]

这样我就可以轻松地在集合中添加和删除用户。

我希望能够将此列表传递给执行某些操作但不修改原始列表的函数,并且它必须保持相同的通用列表类型。

convertAll() 似乎完全按照我的意愿行事,而不必自己用 foreach-object 编写新列表的创建脚本,但我不明白如何利用重载定义(或挺明白他们的意思)。

在 C# 中有很多示例,但我没能找到一个在 PoSH 中演示它的示例。

示例场景:

假设 $DeletedUsers 包含 PSCustomObject 类型的用户对象列表。具有典型的 "User" 属性,例如部门或就业状况。该列表应该能够传递给将更改用户状态的函数 属性,然后可以将其添加到相同 Generic.List 类型的单独输出列表中。

当前示例函数的任何更改。

    Function ProcessUser {

    [Cmdletbinding()]
    Param($DeletedUsers)

    begin{$DeletedUsersClone = $($DeletedUsers).psobject.copy()} #OR similar

    process{
    $DeletedUsersClone | foreach { $_ | Add-Member -NotePropertyName 
    "Processed" -NotePropertyValue "Processed:00"; $Outputlist.add($_)} 
           }
                         }

影响原来的 $DeletedUsers,错误地将处理过的信息添加到应该保持静态的列表中。

有其他方法可以防止这种情况影响脚本的最终 objective,但问题是:

如何使用内置 C# 方法创建 System.Collections 的真实、非引用克隆。Generic.List[System.object]。

诀窍是使用带有显式强制转换为委托类型的脚本块。这看起来像:

$DeletedUsers.ConvertAll([converter[object,object]] {param ($i) <# do convert #> })

注:

  • 后来很明显,OP 正在寻找原始列表的 deep 克隆;即,不仅应该克隆整个列表,而且 它的元素

  • 这个答案只展示了如何创建一个shallow克隆(以及如何以只读方式传递列表).

    • 参见 for a deep-cloning approach based on the .ConvertAll method;对于 [pscustomobject] 个实例,您将使用以下内容(但请注意 .psobject.Copy() 仅创建 个浅[pscustomobject] 个实例本身的副本:

      $DeletedUsers.ConvertAll([converter[pscustomobject, pscustomobject]] {param ($obj) $obj.psobject.copy() })
      

  • 如果您想将列表的浅克隆传递给被调用者:

    • 通过 [Collections.Generic.List[object]]::new($DeletedUsers)(PSv5+ 语法)
    • 或者,如果列表元素的类型未知或者您不想重复,请传递:$DeletedUsers.GetRange(0, $DeletedUsers.Count)
  • 如果您只想防止被调用者意外修改您的列表:

    • 通过 $DeletedUsers.AsReadOnly() - 但是,确实 改变了类型,即 [Collections.ObjectModel.ReadOnlyCollection[object]]