Как преобразовать PSCustomObject с дополнительными реквизитами в пользовательский класс

Есть ли удобный способ преобразовать PSCustomObject в пользовательский класс в качестве параметра функции в PowerShell 5.1? Пользовательский объект содержит дополнительные свойства.

Я хотел бы иметь возможность сделать что-то вроде этого:

class MyClass {
    [ValidateNotNullOrEmpty()][string]$PropA
}

$input = [pscustomobject]@{
    PropA          = 'propA';
    AdditionalProp = 'additionalProp';
}

function DuckTypingFtw {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline)] [MyClass] $myObj
    )
    'Success!'
}

DuckTypingFtw $input

К сожалению, вместо Success! я получаю:

DuckTypingFtw: невозможно обработать преобразование аргумента для параметра «myObj». Невозможно преобразовать значение "@{PropA=propA; AdditionalProp=additionalProp}" в тип "MyClass". Ошибка: «Не удается преобразовать «@{PropA=propA; AdditionalProp=additionalProp}" для
типа "System.Management.Automation.PSCustomObject" для типа "MyClass"." At C:\temp\tmp.ps1:23 char:15 + DuckTypingFtw $input + ~~~~~~ + CategoryInfo: InvalidData: (:) [DuckTypingFtw], ParameterBindingArgumentTransformationException + FullyQualifiedErrorId: ParameterArgumentTransformationError, DuckTypingFtw

Если я закомментирую AdditionalProp, все будет нормально.

По сути, чего я хочу добиться, так это вернуть объект из одной функции и передать его второй функции, в то же время гарантируя, что параметр второй функции имеет все ожидаемые свойства.


person Grzegorz Smulko    schedule 10.10.2019    source источник


Ответы (2)


Если вы создадите конструктор для класса MyClass, который принимает pscustomobject и передает свойство, это должно работать:

class MyClass {
    MyClass([pscustomobject]$object){
        $this.PropA = $object.PropA
    }
    [ValidateNotNullOrEmpty()][string]$PropA
}

$input = [pscustomobject]@{
    PropA          = 'propA';
    AdditionalProp = 'additionalProp';
}

function DuckTypingFtw {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline)] [MyClass] $myObj
    )
    'Success!'
}

DuckTypingFtw $input

редактировать: если вы хотите также использовать MyClass где-то еще, добавьте конструктор по умолчанию для MyClass, например:

class MyClass {
    MyClass() { } 
    MyClass([pscustomobject]$object){
        $this.PropA = $object.PropA
    }
    [ValidateNotNullOrEmpty()][string]$PropA
}
person Jacob Struiksma    schedule 19.03.2020

В своем коде вы определяете два свойства для пользовательского объекта и одно для класса. Вот почему вам нужно либо:

  • чтобы добавить AdditionalProp в свой класс
  • чтобы удалить AdditionalProp из вашего PsCustomObject

Преобразование невозможно по дизайну.

person Zafer Balkan    schedule 10.10.2019
comment
Да, это мелочи, и, как я уже сказал: если я закомментирую AdditionalProp, все будет работать нормально. Я все еще надеюсь, что есть способ - возможно, пользовательский конвертер? - person Grzegorz Smulko; 10.10.2019
comment
Вы можете определить такую ​​функцию, как Map-Property, которая принимает как класс, так и pscustomobject, и использовать для них отражение, возможно, через Get-Member и выполнять итерацию по свойствам. Чтобы вы могли сопоставить их и игнорировать те, которые не отображаются должным образом. - person Zafer Balkan; 10.10.2019
comment
Да, но DuckTypingFtw — общедоступный API, поэтому я не могу ожидать, что потребители будут вызывать Map-Property. Он должен быть прозрачным... - person Grzegorz Smulko; 10.10.2019
comment
Кажется, что единственный способ вернуть экземпляр класса MyClass и никогда не использовать класс pscustomobject. - person Zafer Balkan; 11.10.2019