0

I have been working on a project in Powershell that leverages the Object Oriented nature of the language.

Here's what I am trying to do:

  1. I have created several classes with distinct properties. We can call one of these classes 'ClassA'.

  2. One of the properties of these classes is another class. We can call this 'ClassB'.

  3. I have created several instances of each of these classes.

  4. I need to set parameters of the class, which is a parameter of another class. So, for example: ClassAInstance.ClassBInstance.Property1

  5. I am using a class method to update these parameters.

What i am finding is that when I set one of these lowest level properties, it is updating that parameter on all the instances of the class that previously exist.

What's weird is that the properties of ClassA instances (that are not type ClassB) get updated fine without affecting any existing ClassA instances. The issue is only with properties of ClassB instances, which are properties of ClassA instances.

Any idea why this might be happening?

I apologize for the lack of specifics. It's tough because the code has become pretty complicated, and there is also quite a bit of proprietary information contained within.

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]
            }

        }

    }

}
6
  • Can you post the code for the class definitions? Commented May 21, 2019 at 21:03
  • I can try to redact some stuff and post it in a bit. Would pseudo code be OK? It might be a bit difficult to get working code here without accidentally posting something I'm not allowed to. Commented May 21, 2019 at 21:05
  • Without specifics, what this sounds like is references. Keep in mind that PowerShell objects are in general are always passed as references (not as values). Make sure that you are creating new objects when you are making your assignments. Commented May 21, 2019 at 21:24
  • Thanks @HAL9256 , that is helpful. Here's a snippet from the Method of my higher level class (ClassA): $this.Y1 = New-Object YBlock $this.Y1 = ($this.ClassObject.Y1).PSObject.Copy() Note that "ClassObject" is itself a custom class type. So subsequently, when I update a property of Y1 in this method, shouldn't it be updating the property of a unique object rather than a referenced object? Commented May 21, 2019 at 21:46
  • Can you put the psudo code into the Question? it's hard to read in the comments. Commented May 21, 2019 at 21:48

1 Answer 1

1

In object oriented programming when you copy an object, like you are doing in Y1 = ($this.ClassObject.Y1).PSObject.Copy() that doesn't actually copy the object, that only makes a copy of the object reference (the memory address of where the object actually resides). That is why when you update properties on your seemingly new "Y" object, then set properties, you are also changing the properties of the original object. They both point to the same place in memory.

Sign up to request clarification or add additional context in comments.

4 Comments

That's helpful. So to fix it, would I need to copy all the properties rather than the object itself? Is there an efficient way to do that rather than manually typing out $this.property = $x.property for each one? That's what I did for some of the parameters that actually worked (go figure, should have realized), but I'm wondering if there's a more efficient way?
There is no built in way that I am aware of. You can use reflection but it gets a bit complicated.
OK thanks I will play around with it. I was thinking something like For-Each $property in $class_instance....
I wish it was that simple..here is what it takes in C# code. pluralsight.com/guides/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.