13

托管 PowerShell 运行时是否可以通过PSObject某种方式将其转换回其原始类型?

例如:

我有一个 cmdlet,它在管道中调用WriteObject和推送 ClassXzy 的集合。当我PowerShell.Invoke从事物的主机端调用时,我检索具有属性的PSObjects集合。BaseObject铸造BaseObject失败ClassXyz

有没有办法将每个属性值映射到其对应的原始对象?
我假设 PowerShell 以某种方式执行此操作,因为您可以将PSObjects 传递给 cmdlet 并将它们转换为 Parameter 类型。但是怎么做?

我花了很长时间用 Reflector 研究 PS 组件,但还没有真正确定这种魔法是如何发生的。

有任何想法吗?

编辑:我忘记了一个非常重要的细节。PSObject我正在测试的是一个远程对象,因此该类型BaseObject被命名为Deserialized.ClassXyz. 这就是为什么我看到这种奇怪的行为。

4

3 回答 3

10

在您提到反序列化过程之前,Keith 已经回答了您的问题。

至于序列化/反序列化

我怀疑是否有可能获得原始对象。我不知道 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考虑我上面写的内容时有什么区别,所以我认为在这两种情况下都是不可能的。

于 2010-02-25T05:37:35.367 回答
4

您可以访问BaseObjecton 属性PSObject(遍历每个 PSObject 直到它碰到实际的基础对象)或ImmediateBaseObject仅获取链中的下一个对象。

于 2010-02-25T00:59:57.597 回答
0

您可以执行上述操作,但是一旦 PSRemoting 发挥作用,这些方法将全部失效,因为您将访问代理对象。最佳实践是使用 PSMembers 和 PSProperties

于 2011-12-23T15:52:58.147 回答