Why does Powershell behave this way with classes?

I notice that, when I attempt to create a class B inside a class A declared as Class A{} putting Class B{} inside Class A, it appears the error:

At line:3 char:5
+     {
+     ~
Missing closing '}' in statement block or type definition.
At line:8 char:5
+     }
+     ~
Unexpected token '}' in expression or statement.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingEndCurlyBrace

When I modify Class B{} to B(){}, the program accepts the creation of Class A without problems. If I attempt to insert C(){} in B(){}, then it appears the following error:


At line:6 char:11
+         C(){}
+           ~
An expression was expected after '('.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ExpectedExpression

So I have figured out that, in order to create a class inside a class, create a class inside a class inside a class, and so on, I have to alternate between classes which are declared as Class ClassName(){} and ClassName(){}. Why does that happen and why do the errors happened when I inserted the parenthesis and brackets presumably in a decent way in the code? Thanks.

Can’t really tell you much about the issues with your classes without seeing them.

The first one is Class A{Class B{}}, which returns the first error. Then when I type Class A{B(){}}, the program works fine. When I type Class A{B(){C(){}}}, it returns the second error. Apparently I’ve mistaken a function with a class, because when I type Class A{B(){}}; $AA = New-Object A; $AA.B, it appears


OverloadDefinitions
-------------------
void B()

So I would like to know how to create a class inside a class in Powershell. If someone knows it, please tell me.

it seems PS doesn’t support nested classes, there are 2 workarounds:

https://social.technet.microsoft.com/Forums/en-US/7cb269b3-eb5c-4078-9f12-351d0f76b5ff/how-to-use-nested-c-classes-in-powershell?forum=winserverpowershell

or

This worked:

$sA = @'
  public class A {
    public string s1;
    public class B {
      public string s2;
    }
  }
'@

This didn’t work:

                                       
 public class Turkey
 {
   public Turkey() { }

   public virtual void GetDetails()
   {
     Console.WriteLine("Age: {0}", this.Age);
     Console.WriteLine("Breed: {0}", this.Breed);
   }

   public string Breed
   {
      get;
      set;
   }

   public int Age
   {
      get;
      set;
   }

    /// 

    /// A Wild Turkey is a nested subclass of Turkey
    /// 

    public class WildTurkey : Turkey
    {
    public WildTurkey() { }

    public override void GetDetails()
    {
    base.GetDetails();

    Console.WriteLine("Region: {0}", this.Region);
    }

    public string Region
    {
       get;
       set;
    }
   }
 }

I’ve edited the first code and then inserted the above code in the edited first code, and it worked. Here is the code:

$sA = @'
   public class Turkey
 {
   public Turkey() { }

   public virtual void GetDetails()
   {
     Console.WriteLine("Age: {0}", this.Age);
     Console.WriteLine("Breed: {0}", this.Breed);
   }

   public string Breed
   {
      get;
      set;
   }

   public int Age
   {
      get;
      set;
   }

    /// 

    /// A Wild Turkey is a nested subclass of Turkey
    /// 

    public class WildTurkey : Turkey
    {
    public WildTurkey() { }

    public override void GetDetails()
    {
    base.GetDetails();

    Console.WriteLine("Region: {0}", this.Region);
    }

    public string Region
    {
       get;
       set;
    }
   }
 }

'@

This is a quite weird syntax, to be sincere, so I’ve to accustom myself with it. Furthermore, could someone explain me what is the so-called .NET, whether it is “native” to Powershell, and what is the relationship between the so-called .NET and Powershell. I’ve noticed that there is a similarity between C#, which appears to be related to the so-called .NET, and Powershell. Both C# and Powershell appear to have importing functionalities which use the same resources and they both appear to use stuff with a syntax which goes like Windows.System, System.Objects, etc… Thanks.

How do I access Class B and S2 in this code:

$ClassInstantiation = @'
  public class A {
    public string s1 = "HelloWorld";
    public class B {
      public string s2 = "HelloWorld2";
    }
  }
'@

Add-Type -TypeDefinition $ClassInstantiation -IgnoreWarnings;
$ClassMember = New-Object A;
$ClassMember;

The result of this code is the following:


s1
--
HelloWorld

It doesn’t appear Class B and S2
Edit: In the following code, I can access s2 but not s1:

$sA = @'
  public class A {
    public string s1 = "Hello World";
    public class B {
      public static string s2 = "Hello World 2";
    }
  }
'@

Add-Type -TypeDefinition $sA

[A+B]::s2

The result of the code is:
Hello World 2
If I type [A]::s1, it appears nothing as result.

You can’t access an instance of B if you don’t create one.

Don’t know how to create it in addition to [A+B] but try with: New-Object A.B

See how you marked class b s2 as static? That’s a static property so it can be accessed like shown. Without static it’s an instance method, meaning you have to instantiate an instance of the object to access the property. These are basic class rules, same for c#

1 Like

If I put this in the code:


$sA = @'
  public class A {
    public string s1 = "Hello World";
    public class B {
      public static string s2 = "Hello World 2";
    }
  }
'@

Add-Type -TypeDefinition $sA
New-Object A.B

And press the enter keyboard button, it appears the error as follows:

New-Object : Cannot find type [A.B]: verify that the assembly containing this type is loaded.
At line:12 char:1
+ New-Object A.B
+ ~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
    + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

If I code this


$sA = @'
  public class A {
    public static string s1 = "Hello World";
    public class B {
      public static string s2 = "Hello World 2";
    }
  }
'@

Add-Type -TypeDefinition $sA;
$A = New-Object A;
[A+B]::s2;
[A]::s1;

And press the enter keyboard button, it appears this:

Hello World 2
Hello World

So this works.
I’ve found this works as well:

$Depth1 = @'
public class A
    {
    public string s1 = "Hello World 1";
    public string s2 = "Hello World 2";
    public string s3 = "Hello World 3";
    public class B
        {
        public string s4 = "Hello World 4";
        public string s5 = "Hello World 5";
        public string s6 = "Hello World 6";
        public class C
            {
            public string s7 = "Hello World 7";
            public string s8 = "Hello World 8";
            public string s9 = "Hello World 9";
            }
        public C c;
        public B()
            {
            c = new C();
            }
        }
    public class D
        {
        public string s10 = "Hello World 10";
        public string s11 = "Hello World 11";
        public string s12 = "Hello World 12";
        }
    public B b;
    public D d;
    public A()
    {
    b = new B();
    d = new D();
    }
  }
'@

Add-Type -TypeDefinition $Depth1
$a = New-Object A

The classes must be public for it to work. I can access the variable s4 of class B inside class B through $a.b.s4. When I type [A+B]::s4 in the console and then press the enter keyboard button, the code doesn’t leave any results.

If I write this


$sA = @'
public class A
    {
    public static string s1 = "Hello World 1";
    public static string s2 = "Hello World 2";
    public static string s3 = "Hello World 3";
    public class B
        {
        public static string s4 = "Hello World 4";
        public static string s5 = "Hello World 5";
        public static string s6 = "Hello World 6";
        public class C
            {
            public static string s7 = "Hello World 7";
            public static string s8 = "Hello World 8";
            public static string s9 = "Hello World 9";
            public class D
                {
                public static string s10 = "Hello World 10";
                public static string s11 = "Hello World 11";
                public static string s12 = "Hello World 12";
                }
            }
        }
    }
'@

Add-Type -TypeDefinition $sA;
$A = New-Object A;

Then I press the enter keyboard button, then I can access the class properties using brackets, and I’m not capable of accessing the class properties using a dot, for instance, if I type [A]::S1, I’m capable of accessing the property S1 of A, and if I type $A.S1, I’m not capable of accessing property S1 of A (it shows no result), unlike the function right above this one, which is the inverse.

I think the really important question here is, what are you trying to accomplish?

Is this the question? Typically, you would not create a class “inside” another class. You would extend or inherit from the class. I think if you provided a better “real world” example of what you’re hoping to achieve, we could better assist you.

And of course, if you haven’t done so already, read this article in it’s entirety.

1 Like