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.
[…] blog post is continuation of series of posts on understanding classes in PowerShell. Part 06 of series can be read at here. If you have defined PowerShell class inside a module, its not easy to import class in the current […]
LikeLike