Stefan Lippeck
Stefan Lippeck

Reputation: 455

Powershell: Improve class constructor for IntelliSense support

I worte this class with two custom constructors:


class ExtensionApp {
    [String] $name
    [String] $version
    [String] $path
    [switch] $isContainerPath
    [switch] $useNugetDownloader
    [switch] $force
    [switch] $skipVerification
    
    ExtensionApp() {}

    ExtensionApp(
        [String] $name,
        [String] $version,
        [switch] $useNugetDownloader,
        [switch] $force,
        [switch] $skipVerification
    ) {
        $this.name = $name
        $this.version = $version
        $this.useNugetDownloader = $useNugetDownloader
        $this.force = $force
        $this.skipVerification = $skipVerification

        if (($this.version -eq '') -or ($null -eq $this.version)) {
            #do something
        }
    }
    
    ExtensionApp(
        [String] $name,
        [switch] $isContainerPath,
        [String] $path,
        [switch] $force,
        [switch] $skipVerification
    ) {
        $this.name = $name
        $this.path = $path
        $this.isContainerPath = $isContainerPath
        $this.force = $force
        $this.skipVerification = $skipVerification
    }
}

I'm using those Objects to fill a list i want to process later which looks something like this atm:


$CustApps = New-Object Collections.Generic.List[ExtensionApp]

$CustApps.Add([ExtensionApp]::new('Extension A', '10.0.2554.0', $true , $false, $false)) #first constructor
$CustApps.Add([ExtensionApp]::new('Extension b', $false, '\\server\folder\file.app' , $false, $false)) #second constructor

Thing is: I don't like the way i have to use the constuctors because you dont' get any Intellisense support, and if you have to mix up the constructors while filling the same List, it gets messy.

I could just define a function like this:

function CreateExtensionApp { 
    param(
        [String] $name,
        [String] $version,
        [String] $path,
        [switch] $isContainerPath,
        [switch] $useNugetDownloader,
        [switch] $force,
        [switch] $skipVerification
    ) 
    $new = [ExtensionApp]::new()

    $new.name = $name
    $new.version = $version
    $new.path = $path
    $new.isContainerPath = $isContainerPath
    $new.useNugetDownloader = $useNugetDownloader
    $new.force = $force
    $new.skipVerification = $skipVerification    

    if (($true -eq $new.useNugetDownloader) -and (($new.version -eq '') -or ($null -eq $new.version))) {
        Get-LogiVersion -PackageId $this.name
    }

    return $new    
}

and use that one like this:

$CustApps = New-Object Collections.Generic.List[ExtensionApp]
$CustApps.Add((New-ExtensionAppObj -name 'Extension A' -version '10.0.2554.0' -useNugetDownloader))
$CustApps.Add((New-ExtensionAppObj -name 'Extension B' -path '\\server\folder\file.app' -force -skipVerification))


but i'm kind of a perfectionist and in my opinion, this function should be a static method belonging to the class itself. - I also found a way to do that but it would deprive me of the parameter-names and intellisense support again.

is there a solution that would allow me to use the parameter-names AND have all the code in the class definition?

Upvotes: 1

Views: 244

Answers (1)

mklement0
mklement0

Reputation: 438273

I can't offer a solution, but I'll try to shed some light on the challenges involved:

  • IntelliSense:

    • As of v2022.6.3 of the PowerShell extension for Visual Studio Code, IntelliSense support for calling methods is limited to read-only display of all overloads, and is only shown when the method name has been typed, before typing (

    • In other words, there is currently no support for:

      • (a) showing an overload signature (parameter names) as arguments are being typed.
      • (b) allowing selecting one of the overloads so as to auto-complete a call to that overload with argument placeholders named for the parameters.
    • GitHub issue #1356 discusses potentially improving method-call IntelliSense in the future:

      • (a) is problematic, given PowerShell's lack of static typing, though it's conceivable to let the user manually cycle through available overloads in the same way that the C# extension does, albeit without type awareness.
      • (b) may be feasible, if the IntelliSense feature allows calling a Visual Studio Code snippet in response to a user selection.
  • Self-documenting code:

    • Since all (declared) parameters in PowerShell cmdlets / functions / scripts have names, you always have the option to spell out the target parameter for each argument (though there's often also support for positional arguments for a subset of parameters).

    • Unlike C#, PowerShell, as of PowerShell 7.2.x, does not support named arguments in method calls:

      • That is, the following C# sample call currently has no PowerShell equivalent:

        • C#: string.Compare(strA: "foo", strB: "FOO", ignoreCase: true)
        • PowerShell: [string]::Compare(strA: "foo", strB: "FOO", ignoreCase: $true)
      • GitHub issue #13307 proposes adding support for named arguments.

Upvotes: 1

Related Questions