是否可以使用属性初始化 .NET 类型?

Is it possible to initialize a .NET type with properties?

例如我想使用这个 class Microsoft.HyperV.PowerShell.HardDiskDrive

我试过这样初始化的:

$obbb =  [Microsoft.HyperV.PowerShell.HardDiskDrive]@{
    Path = 'D:\TEST\test\Virtual Hard Disks\test.vhdx'
    DiskNumber = $null
    MaximumIOPS = '1000'
    MinimumIOPS = '0'
    QoSPolicyID = '00000000-0000-0000-0000-000000000000'
    SupportPersistentReservations = $false
    WriteHardeningMethod = '0'
    ControllerLocation = '0'
    ControllerNumber = '0'
    ControllerType = '0'
    Name = 'Hard Drive on IDE controller number 0 at location 0'
    PoolName = 'Primordial'
    Id = 'Microsoft:480244F9-44D4-4BFC-B34B-EC3C425D52F7\83F8638B-8DCA-4152-9EDA-2CA8B33039B4\0\0\D'
    VMId = '480244f9-44d4-4bfc-b34b-ec3c425d52f7'
    VMName = 'test'
    VMSnapshotId = '00000000-0000-0000-0000-000000000000'
    VMSnapshotName = ''
    CimSession = $null
    ComputerName = 'NodeTest'
    IsDeleted = $false
    VMCheckpointId = '00000000-0000-0000-0000-000000000000'
    VMCheckpointName = ''
}

但是出现这个错误:

Cannot convert the "System.Collections.Hashtable" value of type "System.Collections.Hashtable" to type "Microsoft.HyperV.PowerShell.HardDiskDrive".
At line:1 char:1
+ $obbb =  [Microsoft.HyperV.PowerShell.HardDiskDrive]@{
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : ConvertToFinalInvalidCastException

我也尝试过不同的 New-Object 变体 https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/new-object?view=powershell-6

但是有错误。

有没有可能?

谢谢。

Maximilian Burszley 在对问题的评论中提供了关键指针:

PowerShell 的从哈希表中强制转换的构造技术 仅在目标类型(也)具有 构造函数 时才有效:

  • public
  • 无参数

您看到的错误消息暗示 [Microsoft.HyperV.PowerShell.HardDiskDrive] 没有 有这样的构造函数(请参阅底部部分了解如何检查构造函数)。

假设具有此类构造函数的类型具有 public 属性 可设置,您可以从其条目匹配这些属性的任何子集的哈希表进行转换,其中每个条目的键必须是此类属性的名称属性 及其值类型兼容(已经与 属性 类型相同或可转换为它)。
PowerShell 首先使用无参数构造函数实例化类型,然后设置哈希表中指定的 public 属性。

这是一个(有点做作的)例子:

$obj = [System.Exception] @{  # just [Exception] works too, because 'System.' is implied
  HResult = 0x8000400
  Source = 'SomeModule'
}

以上相当于:

$obj = New-Object System.Exception; $obj.HResult = 0x8000400; $obj.Source = 'SomeModule'

由于需要无参数构造函数,散列表技术目前主要用于 DTO-like“属性 包”

If all public 给定类型的构造函数 do 有参数 ,哈希表技术将不起作用,您必须 调用构造函数 以实例化类型 - 通过静态 ::new 方法 (PSv5+)或通过 New-Object cmdlet;例如,调用 [System.DateTime] 构造函数的 (int year, int month, int day) 重载:

New-Object DateTime -ArgumentList 2018, 12, 1 # '-ArgumentList' is optional
[DateTime]::new(2018, 12, 1)  # PSv5+ equivalent

为了调用参数构造函数,可以使用cast替代——见下一节。

然而,an enhancement is coming to PowerShell Core Tip of the hat to TessellatingHeckler. 这将允许使用哈希表技术,即使是带有参数的构造函数,只要哈希表条目集与给定的构造函数重载的参数匹配。


通常,除了上面讨论的哈希表情况,casts ([<target-type>] <operand>) 以及 隐式转换 在以下场景中工作,按考虑顺序排列:

此信息是从 PowerShell Core 的源代码中收集的 here

(a) 如果目标类型装饰有 TypeConverterAttribute attribute that specifies a custom TypeConverter or PSTypeConverter class 支持从操作数类型转换。
或者,这些自定义转换器 classes 可以通过 PowerShell 的 ETS(扩展类型系统)与类型相关联,通过 Update-TypeData -TypeConverter)

(b) 如果目标类型支持从 string 构造实例的静态 ::Parse() 方法:

[DateTime] '2018-12-01'

# The above matches `::Parse()` overload `static datetime Parse(string s)`
# However, given that there's also an overload that accepts a 
# System.IFormatProvider argument, PowerShell uses that in order
# to use *culture-invariant* parsing.
# Thus, the above is the equivalent of:
[DateTime]::Parse('2018-12-01', [cultureinfo]::InvariantCulture)

有关 PowerShell 使用 不变区域性 的更多信息,请参见 this answer

(c) 如果目标类型有一个 public 构造函数,其操作数与以下参数类型相同或兼容:

[Exception] 'Something failed'

# The above matches constructor `Exception(string message)` and is the 
# equivalent of:
New-Object Exception -ArgumentList 'Something failed'
[Exception]::new('Something failed')

(d) 如果目标类型为操作数类型定义隐式或显式 conversion operator

(e) 如果操作数类型实现了 IConvertible 接口,用于构造目标类型的等效实例(仅限于 CLR 运行时类型(内置类型))。


PSv5+中,很容易检查给定(加载)类型的构造函数:调用静态::new 方法,不带括号,它列出了所有 public 可用构造函数的方法重载(签名);使用类型 [System.Random]:

的示例
PS> [Random]::new

OverloadDefinitions
-------------------
System.Random new()
System.Random new(int Seed)

存在 a new() 重载 - 无参数 - 是无参数 public 构造函数 .

的证据

如果根本没有输出,则意味着该类型没有任何 public 构造函数。