Пользовательский хост PowerShell и преобразование PSObject обратно в базовый тип

При размещении среды выполнения PowerShell можно каким-то образом преобразовать PSObject обратно в исходный тип?

Например:

У меня есть командлет, который вызывает WriteObject и отправляет коллекцию ClassXzy в конвейер. Когда я вызываю PowerShell.Invoke со стороны хоста, я получаю набор PSObject со свойством BaseObject. Преобразование BaseObject в ClassXyz не удается.

Есть ли способ сопоставить каждое значение свойства с соответствующим исходным объектом?
Я предполагаю, что PowerShell каким-то образом делает это, поскольку вы можете передать PSObject в командлеты, и они будут преобразованы в типы параметров. Но как?

Я провел много времени, разбираясь в сборках PS с помощью Reflector, но так и не понял, как происходит это волшебство.

Любые идеи?

РЕДАКТИРОВАТЬ: Я забыл одну очень важную деталь. PSObject, с которым я тестирую, является удаленным объектом, поэтому тип BaseObject называется Deserialized.ClassXyz. Вот почему я вижу такое странное поведение.


person Adam Driscoll    schedule 25.02.2010    source источник


Ответы (3)


Кит ответил на ваш вопрос до того, как вы упомянули процесс десериализации.

Что касается сериализации/десериализации

Я сомневаюсь, что можно получить оригинальный объект. Я не знаю, какой тип сериализации использует PowerShell, но если рассмотреть простую сериализацию Xml, то можно понять, что сериализовать можно только свойства и ничего больше.
Вы не можете сериализовать тела его методов.
Вы не можете сериализовать всех подписчиков на это событие (или, может быть, в некоторых случаях это было бы возможно, но я не такой эксперт .NET).
И поскольку тип (как в моем примере) может быть недоступен (например, сборка присутствует только на удаленном компьютере), необходимо передать всю информацию о типе.

Речь идет не только о типе, но и обо всей иерархии наследования и интерфейсах, которые реализует объект. Их бы тоже как-то сериализовали.

Просто попробуйте этот пример:

$deserialized = Start-Job {
    Add-Type -TypeDefinition @"
    public class Parent {
        public override string ToString() { return "overriden parent"; }
        public int IntParent { get { return 1; } }
    }
    public class TestClass : Parent
    {
        public string GString() { return "this is a test string"; }
        public override string ToString() { return "overriden tostring" + System.DateTime.Now.ToString(); }
        public int IntProp { get { return 3451; } }
    }
"@
    New-Object TestClass
} | Wait-Job | Receive-Job
$deserialized.ToString()
$deserialized | gm -for

Вы увидите, что PowerShell

  • сглаживает иерархию наследования.
  • «реализует» только свойства
  • и поскольку он знает значение ToString(), он также может добавить результат метода. Но, как видите, информация, возвращаемая из ToString(), больше не отражает изменение даты — это замороженное значение.

Я не вижу никакой разницы между сериализацией для ремотинга, сериализацией в clixml (через Export-CliXml) или когда Receive-Job учитывая то, что я написал выше, поэтому думаю, что в обоих случаях это невозможно.

person stej    schedule 25.02.2010
comment
Да, ошибка в моем мыслительном процессе заключалась в том, что я совершенно забыл об удаленной части! Имеет смысл, что нет возможности иметь живой объект на другой стороне трубы. Спасибо за хороший пример. - person Adam Driscoll; 25.02.2010

Вы можете получить доступ либо к свойству BaseObject в PSObject (которое обходит каждый PSObject до тех пор, пока он не столкнется с фактическим базовым объектом), либо к ImmediateBaseObject, которое просто захватывает следующий объект в цепочке.

person Keith Hill    schedule 25.02.2010
comment
Я забыл кое-что очень важное. PSObject из удаленной операции. Смотрите мой обновленный вопрос для более подробной информации. Ваш ответ действительно работает для локальных операций. - person Adam Driscoll; 25.02.2010
comment
Удаленное взаимодействие PowerShell использует WSMan/SOAP, поэтому оно не удаляет живые объекты. То, что вы получаете в качестве объекта Deserialized.*, представляет собой просто пакет свойств без обратной связи с исходным объектом. - person Keith Hill; 25.02.2010
comment
Спасибо. Фактор удаленности полностью изменил этот вопрос! - person Adam Driscoll; 25.02.2010

Вы можете делать то, что описано выше, однако все эти методы перестанут работать, как только PSRemoting вступит в игру, так как вы будете обращаться к прокси-объекту. Лучше всего использовать PSMembers и PSProperties.

person Brian Butler    schedule 23.12.2011