【问题标题】:powershell function returning an instance of user defined class will cause returning a new another instance by constructor返回用户定义类的实例的powershell函数将导致构造函数返回一个新的另一个实例
【发布时间】:2020-04-12 13:57:14
【问题描述】:

环境信息:

PS C:\> Get-WmiObject Win32_OperatingSystem


SystemDirectory : C:\Windows\system32
Organization    :
BuildNumber     : 9600
RegisteredUser  : xxxxxxxxxxxxxxxxxxxxxxx
SerialNumber    : xxxxx-xxxxx-xxxxx-xxxxx
Version         : 6.3.9600 # Windows 8.1, Update 1



PS C:\> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.14409.1018
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.14409.1018
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

背景:

我为什么这样做:

  • 我的 USB 硬盘有点不稳定。我需要逐步查找文件和存储路径。
  • 如果会发生错误,请存储错误信息而不是路径。
  • 我打算使用[TreeElement] 对象进行存储和搜索。

我做了一个简单的树类:

# need Powershell v5.0 higher
class TreeElement
{
    $Value = $null
    [System.Collections.Generic.List[TreeElement]] $Children = [System.Collections.Generic.List[TreeElement]]::new()
    [TreeElement] $Parent = $null

    TreeElement($Value)
    {
        $this.Value = $Value
    }

    [TreeElement] AddChild([TreeElement] $Child)
    {
        $this.Children.Add($Child)
        return $Child
    }

    [TreeElement] AddChildValue($ChildValue)
    {
        $Child = [TreeElement]::new($ChildValue)
        $this.Children.Add($Child)
        return $Child
    }
}

我完成了编码,并像这样测试:

$root = [TreeElement]::new(1)
$root.AddChildValue(2)
$root.AddChildValue(3)
$root.AddChildValue(4)
$root.AddChildValue(5)

$root

最后一行将在控制台中显示。

Value Children                                             Parent
----- --------                                             ------
    1 {TreeElement, TreeElement, TreeElement, TreeElement}

没有。

我想将$root 存储到一个文件中。

所以我决定使用*-Clixml,并编码:

Function Store-Tree
{
    [OutputType([void])]
    Param
    (
        [string]$Path,
        [TreeElement]$RootElement
    )

    Export-Clixml -Path $Path -InputObject $RootElement
}

Function Restore-Tree
{
    Param
    (
        [string]$Path
    )

    # restore from xml
    $obj = Import-Clixml -Path $Path

    # Reconstruct instances...
    $result = Reconstruct-Tree -RootObject $obj
    return $result
}

Function Reconstruct-Tree
{
    [OutputType([TreeElement])]
    Param
    (
        [PSObject] $RootObject
    )

    $root = [TreeElement]::new($RootObject.Value)

    foreach($ChildObject in $RootObject.Children)
    {
        [TreeElement] $branch = Reconstruct-Tree $ChildObject
        [void] $root.AddChild($branch)
    }

    return $root
}

然后我测试了它:

PS> mkdir C:\temp
PS> $path = "C:\temp\root-tree.xml"
PS> $root # original instance

Value Children                                             Parent
----- --------                                             ------
    1 {TreeElement, TreeElement, TreeElement, TreeElement}


PS> Store-Tree -Path $path -RootElement $root # store in xml. instances are converted to [PsObject] internally.
PS> $root_r = Restore-Tree -Path $path # restore instances with type of [TreeElement].

Value       Children Parent
-----       -------- ------
TreeElement {}                      # what?

问题:

我预计$root_r 的实例与$root 几乎相同。

$root_r 在 Children 成员中有一个预期的对象。

我只想返回对象。

调试显示,Reconstruct-Tree 函数返回对象时,[TreeElement] 构造函数正在运行。

问题:

有没有办法只返回对象?我是不是做错了什么?

我搜索了一些网站,但没有获得任何信息。

感谢任何帮助。

提前感谢您的帮助。

【问题讨论】:

    标签: powershell class constructor return powershell-5.0


    【解决方案1】:

    自行解决。


    调试步骤 1:

    • 先粘贴代码[A][S]
    • 然后用 [T] 进行测试。
    • 没什么奇怪的。

    调试第二步:

    • 先粘贴代码[A][S]
    • 然后我修改了[TreeElement]这个类[A modified]
    • 粘贴代码[A修改]
    • 然后,使用 [T] 进行测试。
    • 发生了一些奇怪的事情。

    为什么?

    • (1) 当我运行 '[A modified]' 时,它会修复 [TreeElement] 本身的定义。
    • (2) 但是函数Reconstruct-Tree中'[TreeElement]'的定义不固定
    • (3) 所以 (1) 的 [TreeElement] 与 (2) 的 '[TreeElement]' 是不同的类型。
    • (4) 然后Reconstruct-Tree 尝试使用旧的 [TreeElement] 类型('[TreeElement]')返回 [TreeElment] 的实例。
    • (5) 并且powershell判断实例是'[TreeElement]'的构造函数的参数。

    抱歉打扰了。 谢谢。


    示例代码:

    [A] : [TreeElement] 类的定义。

    # need Powershell v5.0 higher
    class TreeElement
    {
        $Value = $null
        [System.Collections.Generic.List[TreeElement]] $Children = [System.Collections.Generic.List[TreeElement]]::new()
        [TreeElement] $Parent = $null
    
        TreeElement($Value)
        {
            $this.Value = $Value
        }
    
        [TreeElement] AddChild([TreeElement] $Child)
        {
            $this.Children.Add($Child)
            return $Child
        }
    
        [TreeElement] AddChildValue($ChildValue)
        {
            $Child = [TreeElement]::new($ChildValue)
            $this.Children.Add($Child)
            return $Child
        }
    }
    

    [A modified] : [TreeElement] 类的新定义。

    class TreeElement
    {
        $Value = $null
        [System.Collections.Generic.List[TreeElement]] $Children = [System.Collections.Generic.List[TreeElement]]::new()
        [TreeElement] $Parent = $null
        [string] $Dummy = "editted class type!"
    
        TreeElement($Value)
        {
            $this.Value = $Value
        }
    
        [TreeElement] AddChild([TreeElement] $Child)
        {
            $this.Children.Add($Child)
            return $Child
        }
    
        [TreeElement] AddChildValue($ChildValue)
        {
            $Child = [TreeElement]::new($ChildValue)
            $this.Children.Add($Child)
            return $Child
        }
    }
    

    [S] : 存储类的实例([TreeElement])。

    Function Store-Tree
    {
        [OutputType([void])]
        Param
        (
            [string]$Path,
            [TreeElement]$RootElement
        )
    
        Export-Clixml -Path $Path -InputObject $RootElement
    }
    
    Function Restore-Tree
    {
        Param
        (
            [string]$Path
        )
    
        # restore from xml
        $obj = Import-Clixml -Path $Path
    
        # Reconstruct instances...
        $result = Reconstruct-Tree -RootObject $obj
        return $result
    }
    
    Function Reconstruct-Tree
    {
        [OutputType([TreeElement])]
        Param
        (
            [PSObject] $RootObject
        )
    
        $root = [TreeElement]::new($RootObject.Value)
    
        foreach($ChildObject in $RootObject.Children)
        {
            [TreeElement] $branch = Reconstruct-Tree $ChildObject
            [void] $root.AddChild($branch)
        }
    
        return $root
    }
    

    [T] : 测试代码。

    $path = "C:\temp\root-tree.xml"
    
    $root = [TreeElement]::new(1)
    $root.AddChildValue(2)
    $root.AddChildValue(3)
    $root.AddChildValue(4)
    $root.AddChildValue(5)
    
    $root # original instance
    
    Store-Tree -Path $path -RootElement $root # store in xml. instances are converted to [PsObject] internally.
    
    $root_r = Restore-Tree -Path $path # restore instances with type of [TreeElement].
    $root_r
    

    【讨论】:

      猜你喜欢
      • 2016-09-16
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-10
      • 2019-04-25
      • 1970-01-01
      相关资源
      最近更新 更多