如何扩展和重写集合类中的 Add

2024-05-12

背景

我在 PowerShell 中有一个具有 4 个属性的数据对象,其中 3 个是字符串,第 4 个是哈希表。我想安排一个新类型,将其定义为该数据对象的集合。

在这个集合类中,我希望强制执行一种特定的格式,这将使我在模块中其他地方的代码更加方便。也就是说,我希望用新的定义覆盖 add 方法,以便 3 个字符串属性的唯一组合将第四个属性添加为哈希表,而 3 个字符串属性的重复项只需使用以下内容更新已存在行的哈希表属性:新的输入哈希表。

这将使我能够抽象集合的扩展,并确保当对其调用 Add 方法时,它将保留我所需的哈希表格式,该哈希表由 3 个字符串属性的唯一组合分组。

我的想法是创建一个扩展集合的类,然后重写 add 方法。

到目前为止的代码

作为下面我的代码的简短描述,有 3 个类:

  1. 基于 3 个字符串属性的命名空间的数据类(我可以在脚本中将其重用于其他用途)。
  2. 专门用于向该数据类添加 id 属性的类。该 id 是哈希表中的键,其值是我的对象命名空间中的配置参数。
  3. 处理这些对象集合的第三个类,我可以在其中定义 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 中使用自定义方法创建自定义集合类型。


It is possible to subclass System.Collections.Generic.List`1 https://docs.microsoft.com/en-US/dotnet/api/System.Collections.Generic.List-1, as this simplified example, which derives from a list with [regex] https://docs.microsoft.com/en-US/dotnet/api/System.Text.RegularExpressions.Regex elements, demonstrates:[1]

using namespace System.Collections.Generic

# Subclass System.Collections.Generic.List`1 with [regex] elements.
class Collection_Configs : List[regex] {

    # Override the .Add() method.
    # Note: You probably want to override .AddRange() too.
    Add([regex] $item) {
      Write-Verbose -Verbose 'Doing custom things...'
      # Call the base-class method.
      ([List[regex]] $this).Add($item)
    }

  }

# Sample use.
$list = [Collection_Configs]::new()
$list.Add([regex] 'foo')
$list

然而,正如你所注意到的,它是建议从基类派生自定义集合System.Collections.ObjectModel.Collection`1 https://learn.microsoft.com/en-US/dotnet/api/System.Collections.ObjectModel.Collection-1:

using namespace System.Collections.ObjectModel

# Subclass System.Collections.ObjectModel`1 with [regex] elements.
class Collection_Configs : Collection[regex] {

    # Override the .Add() method.
    # Note: Unlike with List`1, there is no .AddRange() method.
    Add([regex] $item) {
      Write-Verbose -Verbose 'Doing custom things...'
      # Call the base-class method.
      ([Collection[regex]] $this).Add($item)
    }

  }

至于优点和缺点:

  • List`1比 具有更多的内置功能(方法)ObjectModel`1, 例如.Reverse(), Exists(), and .ForEach().

  • 如果是.ForEach()这实际上有利于ObjectModel`1:没有这样的方法可以避免与 PowerShell 的冲突固有的.ForEach() method https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Arrays#foreach.

请注意,无论哪种情况使用集合应包含的特定类型作为基类的泛型类型参数非常重要: [regex]在上面的例子中,[Model_Config]在您的真实代码中(请参阅下一节)。

  • 如果你使用[object]相反,您的集合将不是类型安全的,因为它将有一个void Add(object item)每当您调用 PowerShell 时都会选择的方法.Add()具有以下类型实例的方法not所需的类型(或无法转换为该类型)。

然而,有一个额外的挑战在你的情况下:

  • 从 PowerShell 7.3.1 开始,因为泛型类型参数确定列表元素类型是另一种习俗class,其他类必须意外加载预先, in a 单独的脚本,定义依赖项的脚本Collection_Configs class.

    • 这个要求是不幸的,并且至少在概念上与确保 .NET 类型中引用的一般(同样不幸)需要相关。class在执行封闭脚本之前已加载定义 - 请参阅这个帖子 https://stackoverflow.com/q/34625440/45375,其接受的答案展示了解决方法。

    • 然而,考虑到所有涉及的类都是同一脚本文件的一部分就您而言,潜在的修复应该比链接帖子中讨论的修复更简单 - 请参阅GitHub 问题 #18872 https://github.com/PowerShell/PowerShell/issues/18872.


[1] Note: There appears to be a bug in Windows PowerShell, where calling the base class' .Add() method fails if the generic type argument (element type) happens to be [pscustomobject] aka [psobject]: That is, while ([List[pscustomobject]] $this).Add($item) works as expected in PowerShell (Core) 7+, an error occurs in Windows PowerShell, which requires the following reflection-based workaround: [List[pscustomobject]].GetMethod('Add').Invoke($this, [object[]] $item)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何扩展和重写集合类中的 Add 的相关文章

随机推荐

  • 在每一帧上更新整个 VBO 是绘制许多变化的独特三角形的最有效方法吗?

    答复我之前的问题 https stackoverflow com questions 24592099 drawing many unique triangles with a single draw call for better per
  • 使标签充当输入按钮

    我怎样才能做一个 a href http test com tag test Test a 就像表单按钮一样 通过充当表单按钮 我的意思是 当单击链接执行操作时method get 或 post 以便能够通过 get 或 post 捕获它
  • Python 中的 Firebase 身份验证时出现 KeyError:“databaseURL”

    相信你做得很好 我是 firebase 的新手 正在尝试进行用户身份验证 我已经安装了pyrebase4并在firebase控制台上创建了一个项目 我还启用了使用 电子邮件和密码 登录并尝试连接我的应用程序 下面是我正在尝试的代码 impo
  • 如何在flutter中实现字母滚动

    有没有任何插件或方法可以在 flutter 中实现这种滚动 具体来说 右侧的字母列 例如突出显示当前字母表字母 或者如果点击某个字母 则滚动视图会直接转到该字母标题 为了按字母顺序排序 我们可以这样做List sort 对于粘性标题 我们也
  • 根据路由隐藏 ng-view DOM 之外的元素

    问题 如何将 登录 视图 路线添加到我的角度应用程序中 隐藏位于ng view DOM 情况 在我的 Angular 页面中 左侧有一个导航树视图 中间有一个主视图 div div class col sm 3 div div div di
  • Java 8根据Map属性过滤Map对象列表以删除一些重复项

    Have a List
  • Angular 5 中使用 rxjs 进行持久订阅

    我对 Angular 5 中的 rxjs 仍然有点陌生 并且很难表达我的问题 我仍然希望得到一些提示 我经常会得到相同的设置 多个组件显示相同的数据 访问数据的单个服务 现在通过 Observables 接收数据时我有 2 个选择 a 订阅
  • 如何在刀片模板中通过引用 @include 来传递变量?

    在 Laravel 4 2 设置中 我在模板中有一个变量 我希望在多个包含之间共享该变量 主刀 This is the variable include header lt in header blade I often use tabin
  • 为什么C++变量是指针时不需要正确定义?

    我对 C 语言完全陌生 特别是指针 经验主要是 PHP 并且希望对以下内容进行一些解释 我已经尝试寻找答案 这两行代码如何能够在我的程序中完成完全相同的工作 第二行似乎违背了我迄今为止所学到和理解的关于指针的一切 char disk 3 D
  • 三星 tab2 平板电脑的 Android 开发

    是否可以使用 Eclipse 在 Samsung Tab 2 平板电脑中开发 Android 应用程序 需要安装什么驱动吗 当然可以 你必须安装标准的android开发工具 SDK ADT ad eclipse Juno最新版本 从这里下载
  • 如何以编程方式生成在图像顶部带有标签的维恩图图像?

    我正在尝试为 pdf 报告生成维恩图 其中文本位于不同区域的顶部 我们使用 htmldoc 生成 pdf 这会排除背景图像之上的文本 我们使用谷歌图表 API 来处理其他图像 但他们的维恩图不支持图表顶部的文本 据我所知 最简单的路径是使用
  • Cocoa 中播客应用程序的 Apple Api

    我正在为 mac 创建一个播客应用程序 用户可以在其中搜索 itunes 上的播客 是否有苹果内置的 api 我可以通过它从苹果 itunes 搜索和播放播客 或任何其他用于从 itunes 搜索播客的 api 谢谢 Edit 现在我找到并
  • 如何从 php 中的 .doc 文件获取页面数,以下代码适用于 .docx 而不是 .doc

    此代码工作 docx 格式文档 但我需要 doc 格式文档计数 php 中的页数 function CountPagesDocx filename zip new ZipArchive if zip gt open filename tru
  • 401 Unauthorized("detail":"未提供身份验证凭据。")

    我在后端使用 djoser 的身份验证 当我通过具有内容类型和授权标头的邮递员在 account me 发出获取请求时 我得到了正确的响应 但是当我尝试从我的角度客户端执行相同的请求时 我得到401 Unauthorized detail
  • .Net Core 中的脚手架以及解决方案中的多个项目

    我创建了一个针对 net461 的 Net Core MVC6 应用程序 我使用了一个我非常熟悉的项目结构 其中我将数据 模型和服务类放置在单独的类库项目中 并且 Web 项目引用这些项目 当我尝试搭建控制器时 我收到一条错误 指出我正在搭
  • __author__ 的起源是什么?

    使用私有元数据变量的约定在哪里 author 一个模块内部从何而来 This http mail python org pipermail python dev 2001 March 013328 htmlPython 邮件列表线程似乎暗示
  • 包含当月所有日期的 PHP 数组 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我正在尝试并且仍然想知道如何获得一个
  • 如何使用 TS 配置 CRA 以支持 nullish-coalescing-operator

    所以我开始了一个新的 CRA 项目 我正在使用 TS beta 来获得一些不错的功能 例如链接运算符 但我也想使用nullish coalescing operator ifExists elseUseThis 不幸的是它不能开箱即用 并告
  • 有效的 URL 分隔符

    我有一个很长的 URL 其中包含多个值 示例1 http www domain com list seach type 0 search period 1 search min 3000 search max 21000 search ar
  • 如何扩展和重写集合类中的 Add

    背景 我在 PowerShell 中有一个具有 4 个属性的数据对象 其中 3 个是字符串 第 4 个是哈希表 我想安排一个新类型 将其定义为该数据对象的集合 在这个集合类中 我希望强制执行一种特定的格式 这将使我在模块中其他地方的代码更加