Understanding Classes in PowerShell – Part 06 – Explaining Inheritance further

This blog post is continuation of series of posts on understanding classes in PowerShell. Part 05 of series can be read at here. In previous blog post, we have learned about meaning of inheritance, define child class and parent class, overload methods, override methods of base class and calling base class members anyhow.

Effect of inheritance on constructors

When we discussed about inheritance, we said that all properties and methods of a base class are inherited. However, constructors (check here on what are constructors and how to define them), are not inherited by a child class. Instead, like all PowerShell classes, the new class is created with a default (parameter-less) constructor. If we think about it, this makes sense after all. The purpose of a constructor is to  initialize the object associated with a class. Again, to find the constructors of a child class, we can use the New static property that PowerShell adds to all classes. (Be sure to use the property, with no parentheses, not the method, with parentheses, which creates a new object).

PS C:\Windows\system32> [history]::new

OverloadDefinitions 
------------------- 
history new() 
history new(System.Object PurchaseAmount)

You can add constructors to the subclass as you would to any class. Remember, that when you add a constructor to the class, it replaces the automatic default constructor. So, if you want a default constructor on your class, you need to add it explicitly. For example, building on our previous history class, we can define default and explicit constructors as:

Class history : book
{
 [String]$HistoryPeriod
 [String]$LastCheckedDate
 [int]$PurchaseAmount

 history(){}

 history($PurchaseAmount){
 $this.PurchaseAmount = 0
 }

 [String] GetLastCheckedDate(){
 if($this.LastCheckedDate -lt $([DateTime]::Today)){
 return $this.LastCheckedDate
 }
 else{
 return ([DateTime]::Today)
 }
 }

 [DateTime] SetLastCheckedDate([DateTime]$Date){
 $this.LastCheckedDate = $Date
 return $this.LastCheckedDate
 }

}

Calling a base class constructor

Consider below code:

Class book
{
 [String]$Category
 [String]$LastCheckedDate
 [int]$PurchaseAmount

book(){}

 book([int]$PurchaseAmount){
 $this.PurchaseAmount = 0
 }

[Void] SetLastCheckedDate([DateTime]$Date){
 $this.LastCheckedDate = $Date
 }
}

Class history : book
{
 [String]$HistoryPeriod
 [String]$LastCheckedDate

history(){}

history([int]$PurchaseAmount){
 $this.PurchaseAmount = 0
 }

[String] GetLastCheckedDate(){
 if($this.LastCheckedDate -lt $([DateTime]::Today)){
 return $this.LastCheckedDate
 }
 else{
 return ([DateTime]::Today)
 }
 }

[DateTime] SetLastCheckedDate([DateTime]$Date){
 $this.LastCheckedDate = $Date
 return $this.LastCheckedDate
 }

}

In above code, we have defined the constructor for both parent and child class with same argument:

book([int]$PurchaseAmount){
 $this.PurchaseAmount = 0
 } 
and:
history([int]$PurchaseAmount){
 $this.PurchaseAmount = 0
 }

It can be argued that we are maintaining essentially the same code. We could have used the base class constructor inside the history class and it would do the job fine. The syntax, for the same is:

Subclass (arguments) : base (argumentsToBaseClassConstructor) { ... }

So, in our case, we could have written history constructor like this:

history([int]$PurchaseAmount) : base([int]$PurchaseAmount){ }

Taking a look at whole code:

Class book
{
 [String]$Category
 [String]$LastCheckedDate
 [int]$PurchaseAmount

book(){}

book([int]$PurchaseAmount){
 $this.PurchaseAmount = 0
 }

[Void] SetLastCheckedDate([DateTime]$Date){
 $this.LastCheckedDate = $Date
 }
}

Class history : book
{
 [String]$HistoryPeriod
 [String]$LastCheckedDate

history(){}

history([int]$PurchaseAmount) : base([int]$PurchaseAmount){ }

[String] GetLastCheckedDate(){
 if($this.LastCheckedDate -lt $([DateTime]::Today)){
 return $this.LastCheckedDate
 }
 else{
 return ([DateTime]::Today)
 }
 }

[DateTime] SetLastCheckedDate([DateTime]$Date){
 $this.LastCheckedDate = $Date
 return $this.LastCheckedDate
 }

}

Note that when creating an instance of a subclass, you cannot call the constructor of a base class. It is error prone and therefore not allowed.

What about sealed classes

The concept of sealed classes in .NET is to define classes for which you cannot define child classes. This is to protect the software from unauthorized development or extension. Most .NET classes are sealed, but the PowerShell classes that you create are not sealed (and the sealed keyword is not valid), so you can use any PowerShell class as a base class. And, you can use .NET classes that are not sealed as an abstract base class inside PowerShell.

One thought on “Understanding Classes in PowerShell – Part 06 – Explaining Inheritance further

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s