【问题标题】:Is it possible to initialize a .NET type with properties?是否可以使用属性初始化 .NET 类型?
【发布时间】:2018-08-27 01:05:03
【问题描述】:

例如我想使用这个类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

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

但出现错误。

有没有可能?

谢谢。

【问题讨论】:

标签: .net powershell constructor initialization hashtable


【解决方案1】:

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

PowerShell 的 construction-by-cast-from-hashtable 技术仅在目标类型(也)具有 constructor 时才有效,即:

  • 公开
  • 无参数

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

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

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

$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 "property bag"

如果所有给定类型的公共构造函数有参数,哈希表技术将不起作用,你必须 调用构造函数以实例化类型 - 通过静态 ::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 到 PowerShell Core TessellatingHeckler 致敬。 这将允许使用哈希表技术,即使具有参数的构造函数,只要哈希表条目集与给定的构造函数重载参数匹配。


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

此信息来自 PowerShell Core 的源代码 here

(a) 如果目标类型用TypeConverterAttribute 属性修饰,该属性指定支持从操作数类型转换的自定义TypeConverterPSTypeConverter 类。
或者,这些自定义转换器类可以通过 PowerShell 的 ETS(扩展类型系统)、Update-TypeData -TypeConverter 与类型相关联)

(b) 如果目标类型支持静态::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) 如果目标类型有一个带有单个参数的公共构造函数,且操作数类型相同或兼容:

[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方法,不带括号,列出方法所有公开可用的构造函数的重载(签名);以[System.Random]类型为例:

PS> [Random]::new

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

new() 重载 - 无参数 - 的存在是无参数公共构造函数的证据

如果根本没有输出,则暗示该类型没有任何公共构造函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-03
    • 2022-08-14
    • 2020-03-27
    • 1970-01-01
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多