Ускорители типов PowerShell: PSObject против PSCustomObject

В 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. Как проверить, возможно, используя отражение, если ускоритель делает что-то другое, а не просто указывает на базовый класс?

person AdamL    schedule 09.03.2016    source источник
comment
Если вы декомпилируете System.Management.Automation.Language.Compiler.VisitConvertExpression, вы увидите, что есть специальная обработка для трех имен типов: ordered, PSCustomObject и ref.   -  person user4003407    schedule 09.03.2016


Ответы (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...

В ускоритель типов добавлено несколько новых статических методов. Я подозреваю, что он использует один из них в качестве конструктора.

person mjolinor    schedule 09.03.2016

[PSObject] и [PSCustomObject] - это псевдонимы для одного и того же типа - System.Management.Automation.PSObject. Я не могу сказать, что для этого есть веская причина, но, по крайней мере, это наводит на мысль о двух разных целях, и, возможно, этого достаточно.

System.Management.Automation.PSObject используется для обертывания объектов. Он был введен для предоставления общего API отражения для любого объекта, который оборачивается PowerShell - .Net, WMI, COM, ADSI или простые пакеты свойств.

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 для определения разницы между простым пакетом свойств и оберткой любого другого объекта.

person Jason Shirk    schedule 13.03.2016
comment
Привет, Джейсон. Оба Get-Member и .GetType() сообщают, что $ o1 и $ o2 являются экземплярами PSCustomObject, а не PSObject. - person Burt_Harris; 16.09.2016
comment
Однако если я создам третий объект как $o3 = [psobject]@{Prop1=42}, этот объект будет другим. - person Burt_Harris; 16.09.2016
comment
Я хочу сказать, что приведенный выше ответ сбивает с толку, потому что в PowerShell [psobject] и [pscustomobject] точно не действуют одинаково. - person Burt_Harris; 16.09.2016
comment
Да, это немного сбивает с толку, отчасти моя вина, отчасти дизайн ... Я пропустил вызов GetType () как способ увидеть PSCustomObject. Преобразование в [pscustomobject] обрабатывается в синтаксическом анализаторе специально, начиная с V3, до этого оно было бы эквивалентно преобразованию в [psobject]. Суть в том, что тип (и экземпляр синглтона) System.Management.Automation.PSCustomObject - это деталь реализации. Приведение [pscustomobject] полезно, если операнд является хеш-литералом, в противном случае оно эквивалентно приведению [psobject]. - person Jason Shirk; 16.09.2016
comment
@JasonShirk, если память не изменяет, использование преобразования [pscustomobject] (n v3 или выше) может дать сбой в определенных ограниченных языковых режимах, тогда как некоторые другие методы (New-Object? Select-Object?) Будут работать в том же контексте. Я не помню подробностей сейчас, потому что узнал (на собственном горьком опыте) несколько лет назад. - person briantist; 03.01.2018