locked
Question about array of objects of type custom class. RRS feed

  • Question

  • Class Tester {
        $alpha=1
    }
    Class Tester2 {
        $beta=[int[]]::new(2)
        $gamma=[Tester[]]::new(2)
    }
    $AVar=[Tester]::new()
    $BVar=[Tester2]::new()
    $Cvar=[Tester[]]::new(2)

    If I run the above script in ISE, and then type $AVar in the shell I get what I would expect:

    PS U:\> $AVar

    alpha
    -----
        1

    If I type $CVar I get nothing, but $CVar.length comes back with 2, so it's set to null.  Typing $BVar further elucidates that point:

    PS U:\> $CVar

    PS U:\> $CVar.Length
    2

    PS U:\> $BVar

    beta   gamma         
    ----   -----         
    {0, 0} {$null, $null}

    Notice beta is initialized to 0, but even though gamma was declared the same way, it is null and not initialized.  If I substitute  

    $gamma=[Tester[]]::new(2) with $gamma=@([Tester]::new(),[Tester]::new()), then it works as expected:

    PS U:\> $BVar

    beta   gamma           
    ----   -----           
    {0, 0} {Tester, Tester}

    How can I create an array of Tester with the ::new() method using a value and have it actually initialize the objects?  using the other method- @([Tester]::new(),[Tester]::new()) would be tedious for more than two objects.  I realize you could probably construct a loop to do this, but I'm wondering if there is a way to modify the constructor in one or both classes or $gamma= statement to accomplish this.

    Thanks

    Monday, August 5, 2019 5:06 PM

All replies

  • [Tester[]]::new(2)

    There is no constructor that takes an int.  The call is ignored.  Thgere is no type that is called "[tester[]]".

    What you are trying to do cannot be done.


    \_(ツ)_/

    Monday, August 5, 2019 5:41 PM
  • Can't you write a custom constructor?  I tried, but none of my attempts worked.  Ok, how do you create an array of objects derived from a custom class?  It must be possible.

    on: (I can't paste a link, docs dot microsoft dot com powershell "about classes")

    You can see where the author does something similar and the array "devices" in this case has $null elements as I have:

    Devices : {$null, $null, $null, $null...}

    Later the $null elements are initialized piecemeal by calling new() for each element in the array.  I am surprised there isn't some way to initialize all at once or at least initialize without an additional call to new()

    Monday, August 5, 2019 9:10 PM
  • Class Tester {
        $alpha = 1
        Tester([int]$n){
            $this.alpha = $n
        }
    }
    [Tester]::New(10)


    \_(ツ)_/

    Monday, August 5, 2019 10:06 PM
  • That doesn't create an array.  It creates a single object and assigns 10 to alpha.
    Monday, August 5, 2019 10:58 PM
  • Why would you think you can create an array. An Array is not a type. It is a collection. You would need to be able to define an array type to do what you are trying to do.  PS classes do not support declaring an array type.

    You can do this:

    Class Tester:System.Collections.ArrayList {
        Tester([string[]]$n){
            $this.AddRange($n)
        }
    }
    $a = 'test1', 'test2', 'test3'
    $t = [tester]::New($a)


    \_(ツ)_/

    Monday, August 5, 2019 11:32 PM
  • You can also do this:

    $ta = New-Object tester[] 10

    Now $ta can only contain objects of type [tester]


    \_(ツ)_/

    Monday, August 5, 2019 11:36 PM
  • Why would I think I could create an array?  Wow.  If you were paying attention it's not that I can't create an array, it's that the elements are all set to $null.  It's easy to show that the array is in fact created just not initialized.  Here is a solution without completely changing the code:

    Class Tester {
        $alpha=777
    }
    Class Tester2 {
        $beta=[int[]]::new(2) # this works as expected, array of two integers initialized to zero
        $gamma=[Tester[]]::new(2) #creates the array, but all elements are $null
        Tester2 () {
            foreach ($_ in 0,1 ) {
                 $this.gamma[$_]=[tester]::new() #initializes the elements from $null to [Tester]
            }
            $this.gamma[1].alpha += 1 #increment 2nd element by 1 just for fun
        }
    }
    PS C:\Users\n> $avar=[tester2]::new()

    PS C:\Users\n> $avar

    beta   gamma           
    ----   -----           
    {0, 0} {Tester, Tester} #now gamma isn't {$null,$null}



    PS C:\Users\n> $avar.gamma

    alpha
    -----
      777
      778



    PS C:\Users\n> $avar.gamma.alpha
    777
    778

    PS C:\Users\n> $avar.gamma[1].alpha
    778

    Tuesday, August 6, 2019 9:15 AM
  • No. You have declared an array of a type. Declaring an array does not create any elements. It just allocates an array of pointers (object references) set to null.  You will have to assign a class instance to each element unfortunately

    PS D:\scripts> $a = New-Object Tester[] 3
    PS D:\scripts> $a[0] = [tester]::New(1)
    PS D:\scripts> $a[1] = [tester]::New(2)
    PS D:\scripts> $a[2] = [tester]::New(3)
    PS D:\scripts> $a|%{$_.local}
    1
    2
    3
    PS D:\scripts> $a.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     Tester[]                                 System.Array
    
    
    PS D:\scripts> $a[0].GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     False    Tester                                   System.Collections.ArrayList
    
    
    PS D:\scripts>
    Note how this behaves.  It is created and exists but appears to be null.  Enumerating returns the elements of the array and we can "peek" inside. 


    \_(ツ)_/


    • Edited by jrv Tuesday, August 6, 2019 10:27 AM
    Tuesday, August 6, 2019 10:26 AM
  • The following allows enumeration and access:

    Class Tester{
        $local = 0
        Tester([int]$i) {
            $this.local = $i
        }
    }
    
    $a = New-Object Tester[] 3
    $a[0] = [tester]::New(1)
    $a[1] = [tester]::New(2)
    $a[2] = [tester]::New(3)
    $a
    


    \_(ツ)_/

    Tuesday, August 6, 2019 10:31 AM
  • There is a syntax that can declare an array of <type> but I do not know the exact syntax.


    \_(ツ)_/

    Tuesday, August 6, 2019 10:33 AM
  • Also you can do it the short way:

    $a = [tester[]][tester]::New(1),[tester]::New(2),[tester]::New(3)


    \_(ツ)_/

    Tuesday, August 6, 2019 10:37 AM
  • We can do this to force the constructor to be called:

    Class Tester{
        $local = 0
        Tester([int]$i) {
            $this.local = 2*$i
        }
    }
    $a = [tester[]]@(1, 2, 3)
    $a


    \_(ツ)_/

    Tuesday, August 6, 2019 10:40 AM
  • Hi,

    Was your issue resolved?

    If you resolved it using our solution, please "mark it as answer" to help other community members find the helpful reply quickly.

    If you resolve it using your own solution, please share your experience and solution here. It will be very beneficial for other community members who have similar questions.

    If no, please reply and tell us the current situation in order to provide further help.

    Best Regards,

    Lee


    Just do it.

    Friday, September 6, 2019 12:51 PM