带点的哈希表键

Hashtable key with point

如何发出带有点字符的散列 table 键,例如 FlatAppearance.BorderSize,以便它是正确的?

$Button = [System.Windows.Forms.Button] @{

    # This is not a valid entry
    FlatAppearance.BorderSize = 0
}
$Button = [System.Windows.Forms.Button] @{

    # This is not a valid entry too
    "FlatAppearance.BorderSize" = 0
}
$Button = [System.Windows.Forms.Button] @{

    # This is not a valid entry too too
    FlatAppearance = @{ BorderSize = 0 }
}

当然可以这么写

$Button = [System.Windows.Forms.Button] @{}
$Button.FlatAppearance.BorderSize = 0

不过写在hash里面更方便table。但是怎么办?谢谢

由于Button type's .FlatAppearance property is of type FlatButtonAppearance在这种情况下没有好的解决方案,因为FlatButtonAppearance类型没有public,无参数构造函数.

如果是这样,你就可以写:

using namespace System.Windows.Forms

$Button = [Button] @{

    # !! This is how you would generally do it, but
    # !! IN THIS CASE IT DOESN'T WORK, due to lack of an appropriate constructor.
    FlatAppearance = [FlatButtonAppearance] @{ BorderSize = 0 }
}

上述语法类似于 C# 的 对象初始化程序 语法,将在下一节中解释。


PowerShell 中的对象初始化语法:

对于从哈希表 (@{ ... }) 或 预先存在的 [pscustomobject] 到类型文字 ([...]) 的转换] instance[1]执行隐式构造(隐式创建实例)然后multi- 属性初始化工作,必须满足以下先决条件

  • 目标类型必须有一个构造函数(可能还有其他[2]),即:

    • public
    • 采用无参数[3]
  • 类型的 public 属性的名称 必须与哈希表条目的键匹配,条目的值必须相同或兼容类型作为目标属性。

这允许 PowerShell 只需调用 new SomeType()(PowerShell 语法中的 [SomeType]::new()),然后从哈希表条目中分配 public 属性的值,即可在后台创建一个实例同名

注意:此类转换在 PowerShell v3+ 中可用,实际上是 语法糖 用于调用
New-Object 带有 -Property 参数的 cmdlet;只有后者适用于 v2.


除了查阅类型的文档外,您还可以通过调用 PowerShell 提供的静态 ::new 方法 在 PowerShell 中轻松地 检查类型的构造函数 括号 (()):

PS> [System.Windows.Forms.FlatButtonAppearance]::new
# NO OUTPUT, which means the type has no public constructors at all.

# [ProcessStartInfo] has several public constructors, among them
# a public parameterless one, so you *can* initialize it by hashtable.
PS> [System.Diagnostics.ProcessStartInfo]::new

OverloadDefinitions
-------------------
System.Diagnostics.ProcessStartInfo new()
System.Diagnostics.ProcessStartInfo new(string fileName)
System.Diagnostics.ProcessStartInfo new(string fileName, string arguments)

确定类型的public,可写实例属性:

PS> [System.Windows.Forms.FlatButtonAppearance].GetProperties('Public, Instance') | 
       ? CanWrite | Select-Object Name, PropertyType

Name               PropertyType        
----               ------------        
BorderSize         System.Int32        
BorderColor        System.Drawing.Color
CheckedBackColor   System.Drawing.Color
MouseDownBackColor System.Drawing.Color
MouseOverBackColor System.Drawing.Color

[1] 例如,这对于从 JSON 反序列化成为 [pscustomobject] 实例的对象很有用;例如:$obj = '{ "Text": "Submit" }' | ConvertFrom-Json; $button = [Button] $obj

[2] 极端情况:不能同时存在具有以下参数类型之一的 参数 public 构造函数,因为它会按原样绑定转换操作数:

  • [object]
  • 从哈希表 (@{ ... }) 转换时:[hashtable][System.Collections.IDictionary]
  • [pscustomobject] 实例投射时:[psobject][pscustomobject]

[3] 方便的是,如果你定义一个类型 (class) 而没有声明 any 构造函数,你会得到一个 public无参数一个默认;例如,在下面的 PowerShell 示例中 class Foo 隐式地 提供了这样一个构造函数:
class Foo { [string] $Bar }; $foo = [Foo] @{ Bar = 'None' }