背景
我在 PowerShell 中有一个具有 4 个属性的数据对象,其中 3 个是字符串,第 4 个是哈希表。我想安排一个新类型,将其定义为该数据对象的集合。
在这个集合类中,我希望强制执行一种特定的格式,这将使我在模块中其他地方的代码更加方便。也就是说,我希望用新的定义覆盖 add 方法,以便 3 个字符串属性的唯一组合将第四个属性添加为哈希表,而 3 个字符串属性的重复项只需使用以下内容更新已存在行的哈希表属性:新的输入哈希表。
这将使我能够抽象集合的扩展,并确保当对其调用 Add 方法时,它将保留我所需的哈希表格式,该哈希表由 3 个字符串属性的唯一组合分组。
我的想法是创建一个扩展集合的类,然后重写 add 方法。
到目前为止的代码
作为下面我的代码的简短描述,有 3 个类:
- 基于 3 个字符串属性的命名空间的数据类(我可以在脚本中将其重用于其他用途)。
- 专门用于向该数据类添加 id 属性的类。该 id 是哈希表中的键,其值是我的对象命名空间中的配置参数。
- 处理这些对象集合的第三个类,我可以在其中定义 add 方法。这就是我遇到问题的地方。
Using namespace System.Collections.Generic
Class Model_Namespace {
[string]$Unit
[string]$Date
[string]$Name
Model_Namespace([string]$unit, [string]$date, [string]$name) {
$this.Unit = $unit
$this.Date = $date
$this.Name = $name
}
}
Class Model_Config {
[Model_Namespace]$namespace
[Hashtable]$id
Model_Config([Model_Namespace]$namespace, [hashtable]$config) {
$this.namespace = $namespace
$this.id = $config
}
Model_Config([string]$unit, [string]$date, [string]$name, [hashtable]$config) {
$this.namespace = [Model_Namespace]::new($unit, $date, $name)
$this.id = $config
}
}
Class Collection_Configs {
$List = [List[Model_Config]]@()
[void] Add ([Model_Config]$newConfig ){
$checkNamespaceExists = $null
$u = $newConfig.Unit
$d = $newConfig.Date
$n = $newConfig.Name
$id = $newConfig.id
$checkNamespaceExists = $this.List | Where { $u -eq $_.Unit -and $d -eq $_.Date -and $n -eq $_.Name }
If ($checkNamespaceExists){
($this.List | Where { $u -eq $_.Unit -and $d -eq $_.Date -and $n -eq $_.Name }).id += $id
}
Else {
$this.List.add($newConfig)
}
}
}
Problem
我希望 Collection_Configs 类扩展内置集合类型并重写 Add 方法。与通用 List 类型一样,我可以简单地输出引用我的集合的变量并自动返回该集合。这样,我就不需要点入 List 属性来访问该集合。事实上,我根本不需要 List 属性。
但是,当我从 System.Array 继承时,我需要在构造函数中提供固定的数组大小。我想避免这种情况,因为我的收藏应该是可变的。我尝试从 List 继承,但无法使语法正常工作; PowerShell 抛出类型未找到错误。
有办法做到这一点吗?
Update
在 mklement 的有用回答之后,我将最后一堂课修改为:
Using namespace System.Collections.ObjectModel
Class Collection_Configs : System.Collections.ObjectModel.Collection[Object]{
[void] Add ([Model_Config]$newConfig ){
$checkNamespaceExists = $null
$newConfigParams = $newConfig.namespace
$u = $newConfigParams.Unit
$d = $newConfigParams.Date
$n = $newConfigParams.Name
$id = $newConfig.id
$checkNamespaceExists = $this.namespace | Where { $u -eq $_.Unit -and $d -eq $_.Date -and $n -eq $_.Name }
If ($checkNamespaceExists){
($this | Where { $u -eq $_.namespace.Unit -and $d -eq $_.namespace.Date -and $n -eq $_.namespace.Name }).id += $id
}
Else {
([Collection[object]]$this).add($newConfig)
}
}
}
这似乎有效。除了继承之外,还必须对如何添加输入类型进行一些其他更正,并且我还需要在其他 2 个类之后单独加载集合类,并在 else 语句中使用基类的 add 方法。
展望未来,我将不得不进行一些其他验证以确保输入 model_config 类型。目前,自定义集合接受任何输入,即使我将添加参数自动转换为 model_config,例如,
$config = [model_config]::new('a','b','c',@{'h'='t'})
$collection = [Collection_Configs]::new()
$collection.Add($config)
有效,但是
$collection.Add('test')
当验证失败时也有效。也许它没有正确覆盖并使用基类的重载?
最后更新
现在一切似乎都正常。该类的最后更新是:
using namespace System.Collections.ObjectModel
Class Collection_Configs : Collection[Model_Config]{
[void] Add ([Model_Config]$newConfig ){
$checkNamespaceExists = $null
$namespace = $newConfig.namespace
$u = $namespace.Unit
$d = $namespace.Date
$n = $namespace.Name
$id = $newConfig.id
$checkNamespaceExists = $this.namespace | Where { $u -eq $_.Unit -and $d -eq $_.Date -and $n -eq $_.Name }
If ($checkNamespaceExists){
($this | Where { $u -eq $_.namespace.Unit -and $d -eq $_.namespace.Date -and $n -eq $_.namespace.Name }).id += $id
}
Else {
[Collection[Model_Config]].GetMethod('Add').Invoke($this, [Model_Config[]]$newConfig)
}
}
}
请注意 else 语句中....GetMethod('Add')...
对于 Windows PowerShell 来说是必要的,正如 mklement0 的超级有用且正确的答案的脚注中指出的那样。如果您能够使用 Core,那么 mklement0 的语法将起作用(我测试过)。
mklement0 也提到,类型需要单独加载。仅供参考,这可以在命令行上完成,以便快速临时测试,方法是输入 model_namespace 和 model_config 类,然后按 Enter 键,然后对 Collection_Configs 执行相同的操作。
总之,这将在 PowerShell 中使用自定义方法创建自定义集合类型。