【问题标题】:PowerShell type accelerators: PSObject vs PSCustomObjectPowerShell 类型加速器:PSObject 与 PSCustomObject
【发布时间】:2016-06-23 23:39:55
【问题描述】:

在 PowerShell v3.0 中引入了PSCustomObject。就像PSObject,但更好。在其他改进中(例如保留属性顺序),从哈希表创建对象得到了简化:

[PSCustomObject]@{one=1; two=2;}

现在看来,这句话很明显:

[System.Management.Automation.PSCustomObject]@{one=1; two=2;}

会以同样的方式工作,因为PSCustomObject 是完整命名空间 + 类名的“别名”。相反,我得到一个错误:

无法将“System.Collections.Hashtable”类型的“System.Collections.Hashtable”值转换为“System.Management.Automation.PSCustomObject”类型。

我列出了这两种对象的加速器:

[accelerators]::get.GetEnumerator() | where key -Like ps*object

    Key            Value
    ---            -----
    psobject       System.Management.Automation.PSObject
    pscustomobject System.Management.Automation.PSObject

并发现两者都引用了相同的 PSObject 类 - 这意味着使用加速器可以做很多其他事情,而不仅仅是缩短代码。

我关于这个问题的问题是:

  1. 您有一些有趣的例子来说明使用加速器与使用完整类型名称之间的区别吗?
  2. 作为一般最佳实践,只要有加速器可用,是否应避免使用完整类型名称?
  3. 如何检查(可能使用反射)加速器是否执行其他操作而不只是指向底层类?

【问题讨论】:

  • 如果你反编译System.Management.Automation.Language.Compiler.VisitConvertExpression,那么你可以看到对orderedPSCustomObjectref这三个类型名称有特殊处理。

标签: powershell powershell-5.0 psobject pscustomobject type-accelerators


【解决方案1】:

[PSObject] 和 [PSCustomObject] 是同一类型的别名 - System.Management.Automation.PSObject。我不能说它有充分的理由,但它至少暗示了两种不同的目的,也许这就是足够的理由。

System.Management.Automation.PSObject 用于包装对象。引入它是为了在 PowerShell 包装的任何对象(.Net、WMI、COM、ADSI 或简单的属性包)上提供通用反射 API。

System.Management.Automation.PSCustomObject 只是一个实现细节。创建 PSObject 时,PSObject 必须包装一些东西。对于属性包,包装的对象是 System.Management.Automation.PSCustomObject.SelfInstance(一个内部成员)。此实例对 PowerShell 的正常使用是隐藏的,观察它的唯一方法是使用反射。

在 PowerShell 中以多种方式创建属性包:

$o1 = [pscustomobject]@{Prop1 = 42}
$o2 = new-object psobject -Property @{Prop1 = 42 }

上面的$o1 和$o2 都将是PSObject 的一个实例,而PSObject 将包装PSCustomObject.SelfInstance。 PSCustomObject.SelfInstance 在 PowerShell 内部用于区分简单属性包和包装任何其他对象。

【讨论】:

  • 嗨杰森。 Get-Member.GetType() 都将 $o1 和 $o2 报告为 PSCustomObject 而不是 PSObject 的实例。
  • 如果我创建第三个对象为$o3 = [psobject]@{Prop1=42},则该对象是不同的。
  • 我的意思是上面的答案令人困惑,因为在 powershell 中 [psobject][pscustomobject] 肯定不一样。
  • 是的,这有点令人困惑,部分是我的错,部分是设计。我错过了调用 GetType() 作为查看 PSCustomObject 的一种方式。从 V3 开始,解析器对转换为 [pscustomobject] 进行了特殊处理,在此之前,它等同于转换为 [psobject]。但底线 - 类型(和单例实例) System.Management.Automation.PSCustomObject 是一个实现细节。如果操作数是散列文字,则强制转换 [pscustomobject] 很有用,否则它等效于 [psobject] 强制转换。
  • @JasonShirk 如果有记忆,使用[pscustomobject] 演员表(n v3 或更高版本)在某些受限语言模式下可能会失败,而其他一些方法(New-Object?Select-Object?)会起作用在相同的上下文中。我现在不记得细节了,因为几年前我(通过艰难的方式)发现了。
【解决方案2】:

查看静态方法:

PS C:\> [PSCustomObject] | gm -Static -MemberType Method



   TypeName: System.Management.Automation.PSObject

Name            MemberType Definition                                                        
----            ---------- ----------                                                        
AsPSObject      Method     static psobject AsPSObject(System.Object obj)                     
Equals          Method     static bool Equals(System.Object objA, System.Object objB)        
new             Method     psobject new(), psobject new(System.Object obj)                   
ReferenceEquals Method     static bool ReferenceEquals(System.Object objA, System.Object o...



PS C:\> [System.Management.Automation.PSCustomObject] | gm -Static -MemberType Method



   TypeName: System.Management.Automation.PSCustomObject

Name            MemberType Definition                                                        
----            ---------- ----------                                                        
Equals          Method     static bool Equals(System.Object objA, System.Object objB)        
ReferenceEquals Method     static bool ReferenceEquals(System.Object objA, System.Object o...

类型加速器添加了几个新的静态方法。我怀疑它使用其中之一作为构造函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-10
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 1970-01-01
    • 2021-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多