Пользовательский хост 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