是否可以在 PowerShell 中创建不可修改的哈希表?

Posted

技术标签:

【中文标题】是否可以在 PowerShell 中创建不可修改的哈希表?【英文标题】:Is it possible to create a non-modifiable hashtable in PowerShell? 【发布时间】:2021-06-25 16:32:50 【问题描述】:

我熟悉使用 Set-Variable 命令在 PowerShell 中创建只读变量和常量,如下所示:

Set-Variable -Option ReadOnly, AllScope -Name STANDARD_TOKEN_PARAMS -Force -Value @
                Username = 'username'
                Password = 'password'
                ClientId = 'clientID'
            

或者替代ReadOnlyConstant 用于不可删除的变量。

我假设使用ReadOnly 选项我将无法修改集合,但事实并非如此。例如,$STANDARD_TOKEN_PARAMS.someNewEntry = 'newEntry' 有效并相应地修改集合。

是否有类似的命令可用于在 PowerShell 中创建真正的“只读”集合?

【问题讨论】:

【参考方案1】:

选项ReadOnlyConstant变量(数据持有者)概念:它们只防止为变量分配新值,它们不会防止修改只读/常量变量不可变存储的

为了防止修改值(对象)本身,你必须另外使用只读的数据类型[1]来存储在只读/常数变量。要获取只读哈希表(字典),请使用通用 System.Collections.ObjectModel.ReadOnlyDictionary[TKey, TValue] 类型:

Set-Variable -Option ReadOnly, AllScope -Name STANDARD_TOKEN_PARAMS -Value $(
    $dict = [System.Collections.Generic.Dictionary[string, string]]::new(
      [System.StringComparer]::OrdinalIgnoreCase
    )
    $dict.Add('Username', 'username')
    $dict.Add('Password', 'password')
    $dict.Add('ClientId', 'clientID')
    [System.Collections.ObjectModel.ReadOnlyDictionary[string, string]]::new($dict)
)

注意:

很遗憾,您不能直接从 PowerShell [hashtable] 初始化 ReadOnlyDictionary[TKey, TValue] 实例,因为需要 通用 IDictionary-实现具有匹配类型的实例;因此,使用了一个辅助的System.Collections.Generic.Dictionar[TKey, TValue] 实例。

注意 [System.StringComparer]::OrdinalIgnoreCase 参数传递给辅助。字典,确保键查找不区分大小写,它们在 PowerShell [hashtables] 中的默认方式。[2]

虽然生成的 $STANDARD_TOKEN_PARAMS 只读变量的 实际上也是只读的,但意外尝试修改只读字典会导致不明显的错误消息,截至PowerShell 核心 7.1:

$STANDARD_TOKEN_PARAMS['Username'] = 'foo' 毫无帮助地报告:Unable to index into an object of type "System.Collections.ObjectModel.ReadOnlyDictionary2[System.String,System.String]` $STANDARD_TOKEN_PARAMS.Add('foo', 'bar') 毫无帮助地报告:Cannot find an overload for "Add" and the argument count: "2" $STANDARD_TOKEN_PARAMS.Clear() 毫无帮助地报告:Cannot find an overload for "Clear" and the argument count: "0". 仅使用 点表示法 会提供有用的错误消息:$STANDARD_TOKEN_PARAMS.Username = 'foo' 报告 Collection is read-only. GitHub issue #15118 建议改进这些错误消息。

[1] 这不是总是必要的,也就是说,如果值是定义 不可变 .NET 原始类型(属性-less 类型,例如 [int]) 或 [string]

[2] 请注意,Windows PowerShell 和(过时的)PowerShell Core 6.1 及更低版本中的[hashtable] 使用[System.StringComparer]::CurrentCultureIgnoreCase,即文化敏感 改为查找 - 有关背景信息,请参阅 this GitHub issue。

【讨论】:

以上是关于是否可以在 PowerShell 中创建不可修改的哈希表?的主要内容,如果未能解决你的问题,请参考以下文章

在 Powershell 中创建多维哈希表数组

我在 ActiveDirectory 中创建了一个新的自定义属性。如何在 PowerShell 中修改它?

我在哪里可以找到可以在 Powershell 中创建的所有 COM 对象?

在 Powershell 中创建 PerformanceCounterCategory

powershell 这是一个脚本,可以在列表中创建网站集,网站,列表和项目。它旨在模拟一个大的创造

powershell PowerShell:在“发送到”文件夹中创建“发送到”快捷方式。