Hi all! Happy Holidays!
First a note: This is not about assigning default values. My examples are simple for the sake brevity. The actual types I’m working with are more complex than [string]
and [int]
and require greater care and the class I’m working with is far more complex. So please, I’m not looking for clever or different ways to set defaults. I’m specifically looking for guidance on calling constructor overloads from other constructor overloads.
I cannot seem to figure out how to call a class constructor from another constructor overload. I have googled for hours and all I get are very basic “intro to PowerShell classes” type results. In other languages, it is a common paradigm to call one constructor from another so the the logic only needs to exist in one constructor overload while several others feed into it with some defaults. It allows for class consumers to more easily work with the class by providing a bunch of extra overloads and class maintainers only need to maintain logic in one overload instead of many.
I have been successful in calling one class method overload from another method overload, but have had no luck with constructors.
For demonstration, here is a simple class with 3 constructor overloads (The ToString()
method is just to make testing a little easier):
class MyClass { [string]$MyString [int]$MyInt MyClass ([int]$Int) { $This.MyInt = $Int $This.MyString = 'No Strings Attached!' } MyClass ([string]$String) { $This.MyInt = 0 $This.MyString = $String } MyClass ([String]$String, [int]$Int) { $This.MyInt = $Int $This.MyString = $String } [string] ToString () { Return "'$($This.MyString)' - '$($This.MyInt)'" } }
Basically, the [string]
overload sets a default for MyInt
and and the [int]
overload sets a default for MyString
, while the overload for both sets both from what is provided.
After creating the class I’m calling the following to test the class constructors:
$MyClass1,$MyClass2,$MyClass3 = $Null,$Null,$Null $MyClass1 = [MyClass]::new(5) $MyClass2 = [MyClass]::new('This is a string') $MyClass3 = [MyClass]::new('This is another string', 15) Write-Host $MyClass1 Write-Host $MyClass2 Write-Host $MyClass3
For the example class, I get these expected results:
'No Strings Attached!' - '5' 'This is a string' - '0' 'This is another string' - '15'
The results listed below are the from running those lines after creating the class.
Now it’s time to refactor this and have the [int]
and [string]
overloads call the overload with both. Here are what I have tried and the results
Calling the constructor as a method on $This
:
(Shows up in intellisense as an available method in ISE)
class MyClass { [string]$MyString [int]$MyInt MyClass ([int]$Int) { $This.MyClass('No Strings Attached!', $Int) } MyClass ([string]$String) { $This.MyClass($String, 0) } MyClass ([String]$String, [int]$Int) { $This.MyInt = $Int $This.MyString = $String } [string] ToString () { Return "'$($This.MyString)' - '$($This.MyInt)'" } }
Result:
Method invocation failed because [MyClass] does not contain a method named 'MyClass'. At line:6 char:13 + $This.MyClass('No Strings Attached!', $Int) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound Method invocation failed because [MyClass] does not contain a method named 'MyClass'. At line:10 char:13 + $This.MyClass($String, 0) + ~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound 'This is another string' - '15'
Calling [MyClass]::New()
:
(I didn’t expect this one to work, anyway)
class MyClass { [string]$MyString [int]$MyInt MyClass ([int]$Int) { [myclass]::new('No Strings Attached!', $Int) } MyClass ([string]$String) { [myclass]::new($String, 0) } MyClass ([String]$String, [int]$Int) { $This.MyInt = $Int $This.MyString = $String } [string] ToString () { Return "'$($This.MyString)' - '$($This.MyInt)'" } }
Result:
'' - '0' '' - '0' 'This is another string' - '15'
Calling [MyClass]::New()
and assigning it to $this
:
Note of Caution: Using this method I have managed to crash PowerShell several times, especially when working with System.IO
streams as members.
class MyClass { [string]$MyString [int]$MyInt MyClass ([int]$Int) { $This = [myclass]::new('No Strings Attached!', $Int) } MyClass ([string]$String) { $This = [myclass]::new($String, 0) } MyClass ([String]$String, [int]$Int) { $This.MyInt = $Int $This.MyString = $String } [string] ToString () { Return "'$($This.MyString)' - '$($This.MyInt)'" } }
Result:
'' - '0' '' - '0' 'This is another string' - '15'
Calling MyClass
as a command/function:
(This is how it is done in C#)
class MyClass { [string]$MyString [int]$MyInt MyClass ([int]$Int) { MyClass('No Strings Attached!', $Int) } MyClass ([string]$String) { MyClass($String, 0) } MyClass ([String]$String, [int]$Int) { $This.MyInt = $Int $This.MyString = $String } [string] ToString () { Return "'$($This.MyString)' - '$($This.MyInt)'" } }
Result:
MyClass : The term 'MyClass' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:6 char:13 + MyClass('No Strings Attached!', $Int) + ~~~~~~~ + CategoryInfo : ObjectNotFound: (MyClass:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException MyClass : The term 'MyClass' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:10 char:12 + MyClass($String, 0) + ~~~~~~~ + CategoryInfo : ObjectNotFound: (MyClass:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException 'This is another string' - '15'
Calling This
as a command/function:
(I don’t even know anymore… Grasping at straws)
class MyClass { [string]$MyString [int]$MyInt MyClass ([int]$Int) { This('No Strings Attached!', $Int) } MyClass ([string]$String) { This($String, 0) } MyClass ([String]$String, [int]$Int) { $This.MyInt = $Int $This.MyString = $String } [string] ToString () { Return "'$($This.MyString)' - '$($This.MyInt)'" } }
Result:
This : The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:6 char:13 + This('No Strings Attached!', $Int) + ~~~~ + CategoryInfo : ObjectNotFound: (This:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException This : The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:10 char:12 + This($String, 0) + ~~~~ + CategoryInfo : ObjectNotFound: (This:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException 'This is another string' - '15'
I’m beginning to think this is just not possible. Anyone know for certain how to do this?
submitted by /u/markekraus
[link] [comments]
The post Can a PowerShell v5 Class Constructor be called from another Overload Constructor? appeared first on How to Code .NET.