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

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

Например:

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

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

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

Есть идеи?

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

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 учитывая то, что я написал выше, я думаю, что в обоих случаях это невозможно.

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

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

Другие вопросы по тегам