【问题标题】:Issue with Class Instances in PowershellPowershell 中的类实例问题
【发布时间】:2019-05-22 07:58:47
【问题描述】:

我一直在利用 Powershell 语言的面向对象特性开展一个项目。

这是我想要做的:

  1. 我创建了几个具有不同属性的类。我们可以将这些类之一称为“ClassA”。

  2. 这些类的属性之一是另一个类。我们可以称之为“ClassB”。

  3. 我为每个类创建了几个实例。

  4. 我需要设置类的参数,这是另一个类的参数。因此,例如:ClassAInstance.ClassBInstance.Property1

  5. 我正在使用类方法来更新这些参数。

我发现,当我设置这些最低级别的属性之一时,它正在更新以前存在的类的所有实例上的该参数。

奇怪的是 ClassA 实例(不是 ClassB 类型)的属性可以很好地更新,而不会影响任何现有的 ClassA 实例。问题仅在于 ClassB 实例的属性,即 ClassA 实例的属性。

知道为什么会发生这种情况吗?

对于缺乏细节,我深表歉意。这很难,因为代码变得相当复杂,而且其中还包含相当多的专有信息。

Class XBlock
{
    [string]$Name
}

Class YBlock: XBlock
{
    [string]$Name = 'Y1'
    [float]$High_Scale = 100
}

Class XClass
{
    [string]$Name = ''
    [System.Collections.ArrayList]$CodeBlock

    SetXParams()
    {
        $blocknames = New-Object System.Collections.Arraylist

        for ($i = 1; $i -le $this.XBlocks; $i++)
        {
            $blocknames.add("X$i")
        }

        $blocknames | %{

            $this.$_ = New-Object XBlock

            $pattern = -join ('Attribute_Instance Name="', $_, '/High_Scale')
            $match = $this.CodeBlock | Select-String -Pattern $pattern -Context 0, 2 -ErrorAction SilentlyContinue
            If ($match.count -gt 0)
            {
                $this.$_.High_Scale = ($match[0].Context.PostContext[1]).split('=').split(' ')[7]
            }       

        }
    }   
}

class YClass: XClass
{
    [int]$YBlocks = 1
    [YBlock]$Y1
}

Class XModule
{
    [string]$Name = ''
    [string]$Class = ''
    [System.Collections.ArrayList]$CodeBlock
    [int]$XBlocks = 0

    [System.Collections.ArrayList]$CodeBlock

    SetModuleParams([XModule]$XModule)
    {
        $this.Name = $XModule.Name

        $this.CodeBlock = $XModule.CodeBlock

        $this.ClassObject = ($Global:AllClasses | ? { $_.Name -eq $this.Class }).PSObject.Copy()

    }

    SetYParams()
    {
        $blocknames = New-Object System.Collections.Arraylist


        for ($i = 1; $i -le $this.XBlocks; $i++)
        {
            $blocknames.add("Y$i")
        }

        $blocknames | %{

            $this.$_ = New-Object YBlock
            $this.$_ = $this.ClassObject.$_.PSObject.Copy()

            $pattern = -join ('(Attribute Instance Name="', $_, '.*High_Scale)')
            $match = $this.CodeBlock | Select-String -Pattern '(Attribute Instance Name=".*High_Scale)' -Context 0, 2 #-ErrorAction SilentlyContinue -SimpleMatch $true
            If ($match.count -gt 0)
            {
                $this.$_.High_Scale = ($match[0].Context.PostContext[1]).split('=').split(' ')[7]
            }

        }

    }

}

【问题讨论】:

  • 你能贴出类定义的代码吗?
  • 我可以尝试编辑一些内容并稍后发布。伪代码可以吗?在不意外发布我不允许发布的内容的情况下,在此处获取工作代码可能有点困难。
  • 没有细节,这听起来像是引用。请记住,PowerShell 对象通常始终作为引用(而不是值)传递。确保在进行分配时创建新对象。
  • 感谢@HAL9256,这很有帮助。这是我的更高级别类(ClassA)的方法中的一个 sn-p: $this.Y1 = New-Object YBlock $this.Y1 = ($this.ClassObject.Y1).PSObject.Copy() 请注意“ClassObject”本身就是一个自定义类类型。那么随后,当我在此方法中更新 Y1 的属性时,它不应该更新唯一对象的属性而不是引用对象的属性吗?
  • 你能把伪代码放到问题里吗?在 cmets 中很难阅读。

标签: powershell oop powershell-4.0


【解决方案1】:

在面向对象编程中,当你复制一个对象时,就像你在Y1 = ($this.ClassObject.Y1).PSObject.Copy() 中所做的那样,它实际上并没有复制对象,它只是复制了对象引用(对象实际所在的内存地址) .这就是为什么当您更新看似新的“Y”对象的属性,然后设置属性时,您也在更改原始对象的属性。它们都指向内存中的同一个地方。

【讨论】:

  • 这很有帮助。所以要修复它,我需要复制所有属性而不是对象本身吗?有没有一种有效的方法来做到这一点,而不是手动输入 $this.property = $x.property ?这就是我为一些实际工作的参数所做的(去图,应该已经意识到),但我想知道是否有更有效的方法?
  • 没有我知道的内置方式。您可以使用反射,但它会有点复杂。
  • 好的,谢谢,我会玩的。我在想类似 For-Each $property in $class_instance....
  • 我希望它是那么简单..这就是它在 C# 代码中所需要的。 pluralsight.com/guides/…
猜你喜欢
  • 1970-01-01
  • 2017-08-27
  • 2014-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多