正如已经指出的那样,由于效率低下,因此值得改变您的方法:
如果新元素与Select-Object -Unique 重复,则不要盲目地附加然后可能删除它,而是使用 测试 来决定一个元素是需要附加还是已经存在。
Patrick's helpful answer 是这种优化方法的直接实现,它将大大加快您的代码速度,并且应该可以接受,除非数组列表变得非常大。
作为这种优化的一个副作用 - 因为数组列表只使用.Add() 就地修改 - 你原来的问题就消失了。
按要求回答问题:
如果您希望它们即使在以后的分配过程中也保留给定类型,只需类型约束您的(成员)变量。
也就是说,就像您对$name 所做的那样,将您希望成员约束的类型放在成员变量声明的左侧:
[System.Collections.ArrayList] $parents
[System.Collections.ArrayList] $children
[System.Collections.ArrayList] $members
但是,这会将这些成员变量初始化为$null,这意味着您将不能只在.add*() 方法中调用.Add();因此,构造一个(最初为空的)实例作为声明的一部分:
[System.Collections.ArrayList] $parents = [System.Collections.ArrayList]::new()
[System.Collections.ArrayList] $children = [System.Collections.ArrayList]::new()
[System.Collections.ArrayList] $members = [System.Collections.ArrayList]::new()
此外,您确实必须在您的 Select-Object -Unique 管道周围使用 @(...);虽然这确实输出了一个数组(类型为[object[]]),但类型约束会导致该数组转换为[System.Collections.ArrayList] 实例,如下所述。
@(...) 的需求有点令人惊讶 - 见底部。
类型约束说明:
本质上,这与参数变量中使用的技术相同,也可以用于常规变量中。
- 使用常规变量(函数或脚本中的局部变量),您必须还初始化变量以使类型约束起作用(使变量均匀被创建);例如:
[System.Collections.ArrayList] $alist = 1, 2
应用于您的代码的简化版本:
Class OrgUnit
{
[string] $name
# Type-constrain $children too, just like $name above, and initialize
# with an (initially empty) instance.
[System.Collections.ArrayList] $children = [System.Collections.ArrayList]::new()
addChild($child){
# Add a new element.
# Note the $null = ... to suppress the output from the .Add() method.
$null = $this.children.Add($child)
# (As noted, this approach is inefficient.)
# Note the required @(...) around the RHS (see notes in the last section).
# Due to its type constraint, $this.children remains a [System.Collections.ArrayList] (a new instance is created from the
# [object[]] array that @(...) outputs).
$this.children = @($this.children | Select-Object -Unique)
}
}
有了类型约束,.children 属性现在仍然是[System.Collections.ArrayList]:
PS> $ou = [OrgUnit]::new(); $ou.addChild(1); $ou.children.GetType().Name
ArrayList # Proof that $children retained its type identity.
注意:需要@(...) - 以确保数组赋值以成功转换为[System.Collections.ArrayList] - 有点令人惊讶,因为以下适用于类似的 generic 列表类型 [System.Collections.Generic.List[object]]:
# OK: A scalar (single-object) input results in a 1-element list.
[System.Collections.Generic.List[object]] $list = 'one'
相比之下,这不适用于[System.Collections.ArrayList]:
# !! FAILS with a scalar (single object)
# Error message: Cannot convert the "one" value of type "System.String" to type "System.Collections.ArrayList".
[System.Collections.ArrayList] $list = 'one'
# OK
# Forcing the RHS to an array ([object[]]) fixes the problem.
[System.Collections.ArrayList] $list = @('one')