powershell 如何扩展字典类

xkftehaa  于 2023-06-06  发布在  Shell
关注(0)|答案(1)|浏览(214)

我想在PowerShell中创建一个自定义字典类(它将配置临时存储在特定的第三方应用程序中,并在另一个PowerShell会话中检索它)。从技术上讲,我也可以通过创建一种Set-MyConfigVariable -Key <key> -Value <Value>Get-MyConfigVariable -Key <key> cmdlet来做到这一点,但我想研究一下是否可以使用扩展字典(并在gettersetter方法中挂钩)来更友好地使用用户(作者)。
简而言之,在C#中描述的内容如下:How to write a getter and setter for a Dictionary?

Class MyStore: System.Collections.Generic.Dictionary[String,String] {
    $h = @{}
    [string]$This([String]$Key) {
        get { write-host 'getting something'; return $h[$Key] }
        set { write-host 'setting something'; $h[$Key] = $Value }
    }
}

$MyStore = [MyStore]::new()
$MyStore['key'] = 'value'
$MyStore['key']

上述原型在[string]$This([String]$Key) {indexer?),但可能还需要不同的getter和setter实现(使用Update-TypeData?).
如何在PowerShell中做到这一点(如果可能的话)?
如果对一个类来说不可能,那么可以在单个示例上(使用动态键)完成吗?

iqjalb3h

iqjalb3h1#

PowerShell代码,使用自定义class es,从PowerShell 7.3.4开始有以下限制

  • 通常 * 不 * 支持属性 getterssetters -GitHub issue #2219建议添加对它们的支持。
  • 现在,* 常规 * 属性的getter和setter可以 * 模拟 *,使用Add-MemberScriptProperty成员,如this answer.Tip of the hat to Santiago Squarzon所示。
  • 但是,对于实现 * 参数化 * 属性,***没有 * 解决方法,而实现 * 索引器***则需要解决方法。
    C#代码,用Add-Type临时编译,提供了一个解决方案
    • Dictionary[String,String]派生 * 您的自定义类-正如您所尝试的那样-是有问题的,因为它需要使用new关键字 * 隐藏 * 基类成员,在PowerShell代码中-至少从PowerShell 7.3.4开始-不完全支持-请参阅GitHub issue #19649
  • 但是,您可以使您的自定义类 * Package * 字典类型,并通过类型特定的索引器(参数化属性)提供对其的访问,您可以将PowerShell脚本块挂接到其中以执行。

请参见以下示例实现

Add-Type @'
using System;
using System.Collections.Generic;
using System.Management.Automation;
public class CustomDict
{
  // The dictionary to wrap.
  Dictionary<string, string> _dict = new ();
  // The hook script blocks.
  ScriptBlock _getHook, _setHook;
  // Constructor
  public CustomDict(ScriptBlock getHook = null, ScriptBlock setHook = null)
  {
    _getHook = getHook; _setHook = setHook;
  }
  // Implement an indexer that provides access to the wrapped 
  // dictionary's, while also executing the "event"-hook script blocks.
  public string this[string key]
  {
      get { 
        _getHook?.Invoke(_dict, key);
        return _dict[key]; 
      }
      set { 
        _setHook?.Invoke(_dict, key, value);
        _dict[key] = value;
      }
  }
}
'@

# Construct an instance with both GET and SET hooks (script blocks).
$o = [CustomDict]::new(
  { param($dict, $key) Write-Verbose -Verbose "getting entry '$key'" }, 
  { param($dict, $key, $value )Write-Verbose -Verbose "setting '$key' to '$value'" }
)

# Create an entry...
$o['foo'] = 'bar'
# ... and report its value
$o['foo']

输出:

VERBOSE: setting 'foo' to 'bar'
VERBOSE: getting entry 'foo'
bar

注意事项:

  • 作为钩子传递的脚本块在调用者的 child 作用域中执行。

相关问题