gpt4 book ai didi

powershell - 替代全局变量或单例

转载 作者:行者123 更新时间:2023-12-02 23:17:17 24 4
gpt4 key购买 nike

我在不同的地方读到全局变量充其量只是一种代码味道,最好避免。目前我正在将一个基于大函数的 PS 脚本重构为类,并考虑使用 Singleton。用例是一个大型数据结构,需要从许多不同的类和模块中引用。
然后我找到了this ,这似乎表明单例也是一个坏主意。

那么,创建一个需要被许多类引用并被其中一些类修改的单一数据结构的正确方法是什么(在 PS 5.1 中)?可能相关的事实是我不需要它是线程安全的。根据定义,队列将以非常线性的方式处理。

FWIW,我到引用的链接查找有关单例和继承的信息,因为我的单例只是许多具有非常相似行为的类之一,我从包含下一个类的集合的单例开始,每个类都包含集合下一个类,创建一个分层队列。我希望有一个处理所有常见队列管理的基类,然后为每个类的不同功能扩展它。除了让第一个扩展类成为单例之外,这很好用。这似乎是不可能的,对吧?

编辑:或者,是否有可能使用通用列表属性方法中的这个嵌套类能够从子级中识别父级?这就是我的处理方式,这是基于函数的版本。全局[XML]变量形成了数据结构,我可以使用 .SelectNode() 单步执行该结构。填充一个变量以传递给下一个函数,并使用 .Parent从更高层获取信息,尤其是从数据结构的根部获取信息。

编辑:由于我现在似乎无法在此处粘贴代码,因此我在 GitHub 上有一些代码.此处的单例示例在第 121 行,我需要验证是否还有其他相同任务的示例尚未完成,因此我可以跳过除最后一个实例之外的所有示例。这是删除各种 Autodesk 软件的通用组件的概念证明,这些组件以非常临时的方式进行管理。因此,我希望能够安装任何程序(包)组合并按任何计划进行卸载,并确保具有共享组件卸载的最后一个包是卸载它的包。以免在最后一次卸载发生之前破坏其他依赖程序。希望这是有道理的。欧特克安装是痛苦的。如果您不必与他们打交道,请认为自己很幸运。 :)

最佳答案

补充Mathias R. Jessen's helpful answer - 这很可能是您问题的最佳解决方案 - 回答您的原始问题:

So, what IS the right way (in PS 5.1) to create a single data structure that needs to be referenced by a lot of classes, and modified by some of them [without concern for thread safety]?


  • 主要原因要避免的全局变量是它们是 session 全局的 ,这意味着在您自己的代码之后执行的代码也会看到这些变量,这可能会产生副作用。
  • 您无法在 PowerShell 中实现真正的单例 ,因为 PowerShell 类不支持访问修饰符;值得注意的是,您不能将构造函数设为私有(private)(非公共(public)),您只能使用 hidden 将其“隐藏”。关键字,这只会使其难以被发现,同时仍然可以访问。
  • 您可以使用以下技术逼近单例 ,它本身模拟一个静态类(PowerShell 也不支持,因为 static 关键字仅在类成员上受支持,而不是整个类)。

  • 一个简单的例子:
    # NOT thread-safe
    class AlmostAStaticClass {
    hidden AlmostAStaticClass() { Throw "Instantiation not supported; use only static members." }
    static [string] $Message # static property
    static [string] DoSomething() { return ([AlmostAStaticClass]::Message + '!') }
    }
    [AlmostAStaticClass]::<member> (例如 [AlmostAStaticClass]::Message = 'hi' )现在可以在 AlmostAStaticClass 的范围内使用已定义和所有后代范围(但它在全局范围内不可用,除非定义范围恰好是全局范围)。

    如果您需要跨模块边界访问该类,您可以将其作为参数(作为类型文字)传递;请注意,您仍然需要 ::访问(总是静态的)成员;例如。, & { param($staticClass) $staticClass::DoSomething() } ([AlmostAStaticClass])
    实现线程安全的准单例 - 也许是为了使用
    ForEach-Object -Parallel (v7+) 或 Start-ThreadJob (v6+,但可在 v5.1 上安装)- 需要 更多工作 :

    笔记:
  • 然后需要方法来获取和设置概念上的属性,因为 PowerShell 从 7.0 开始不支持代码支持的属性 getter 和 setter (添加此功能是 this GitHub feature request 的主题)。
  • 但是,您仍然需要一个基础属性,因为 PowerShell 不支持字段;再次,您能做的最好的事情就是隐藏这个属性,但它在技术上仍然可以访问。

  • 以下 示例使用 System.Threading.Monitor (这是 C# 的 lock 语句所基于的)来管理对值的线程安全访问;对于 管理从集合中同时添加和删除项目 , 使用 thread-safe collection types 来自 System.Collections.Concurrent命名空间。
    # Thread-safe
    class AlmostAStaticClass {

    static hidden [string] $_message = '' # conceptually, a *field*
    static hidden [object] $_syncObj = [object]::new() # sync object for [Threading.Monitor]

    hidden AlmostAStaticClass() { Throw "Instantiation not supported; use only static members." }

    static SetMessage([string] $text) {
    Write-Verbose -vb $text
    # Guard against concurrent access by multiple threads.
    [Threading.Monitor]::Enter([AlmostAStaticClass]::_syncObj)
    [AlmostAStaticClass]::_message = $text
    [Threading.Monitor]::Exit([AlmostAStaticClass]::_syncObj)
    }

    static [string] GetMessage() {
    # Guard against concurrent access by multiple threads.
    # NOTE: This only works with [string] values and instances of *value types*
    # or returning an *element from a collection* that is
    # only subject to concurrency in terms of *adding and removing*
    # elements.
    # For all other (reference) types - entire (non-concurrent)
    # collections or individual objects whose properties are
    # themselves subject to concurrent access, the *calling* code
    # must perform the locking.
    [Threading.Monitor]::Enter([AlmostAStaticClass]::_syncObj)
    $msg = [AlmostAStaticClass]::_message
    [Threading.Monitor]::Exit([AlmostAStaticClass]::_syncObj)
    return $msg
    }

    static [string] DoSomething() { return ([AlmostAStaticClass]::GetMessage() + '!') }

    }

    请注意,与跨越模块边界类似,使用线程也需要将类作为类型对象传递给其他线程,但是使用 $using: 更方便地完成。范围说明符;一个简单(人为)的例子:
    # !! BROKEN AS OF v7.0
    $class = [AlmostAStaticClass]
    1..10 | ForEach-Object -Parallel { ($using:class)::SetMessage($_) }

    备注 : 这个跨线程使用其实是 从 v7.0 开始损坏 , 由于类当前被绑定(bind)到定义的运行空间 - 见 this GitHub issue .是否会提供解决方案还有待观察。

    如您所见,PowerShell 类的局限性使得实现此类场景很麻烦;使用 Add-Type 使用临时编译的 C# 代码值得考虑作为替代方案。

    这个GitHub meta issue是与 PowerShell 类有关的各种问题的汇编 ;虽然他们最终可能会得到解决, PowerShell 的类不太可能达到与 C# 相同的功能 ;毕竟,OOP 不是 PowerShell 脚本语言的重点(除了使用预先存在的对象)。

    关于powershell - 替代全局变量或单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62018179/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com