3
\$\begingroup\$

I am playing with learning PowerShell classes, and I have a validation situation that kind of lends itself to Enums, as shown in the first example. With Enum

Enum pxPathType {
  FileSystem_Folder = 0
  FileSystem_File   = 1
  Registry_Key      = 2
  Registry_Property = 3
}

class PxConstant {
    # Static Properties
    static [string] $RegExPathWithWildcard = '\\\*\.\*$|\\\*|\\.\.\*$|\*\.(\?[a-zA-Z0-9\?]{2}|[a-zA-Z0-9\?]\?[a-zA-Z0-9\?]|[a-zA-Z0-9\?]{2}\?)$|\\[^\\]*\.(\?[a-zA-Z0-9\?]{2}|[a-zA-Z0-9\?]\?[a-zA-Z0-9\?]|[a-zA-Z0-9\?]{2}\?)$|\\[^\\]*\.\*$'
}

class PxPath {
    # Properties
    [string]$Type = $null

    # Constructors
    PxPath ([string]$path) {
        $this.Type = [PxPath]::PathType($path)
    }
    PxPath ([string]$path, [string]$pathType) {
        #$pathTypeEnum = try {
        $this.Type = try {
            [pxPathType] $pathType 
        } catch { 
            Throw "Not a valid path type: $pathType"
        }
    }

    static [String] PathType ([String]$path) {
        [string]$pathType = $null
        if ($path -match [PxConstant]::RegExPathWithWildcard) {
            $pathWithoutWildcard = $path -replace [regex]::escape($matches[0]), ''
            Write-Host $pathWithoutWildcard
        }
        return $pathType
    }
}

$pathType = 'FileSystem_Folders'
$path = try {
    [PxPath]::New("C:\", $pathType)
} catch {
    Write-Host "$($_.Exception.Message)"
}
$path = try {
    [PxPath]::New("\\Server\Folder\*")
} catch {
    Write-Host "$($_.Exception.Message)"
}

The issue I have is that the Enum is only EVER used in the PxPath class, and I feel like that means I should have the Enum in the class, so it's self contained. However, PS5 doesn't allow an Enum in a class. The workaround I have come up with is to instead use an array as a hidden Property of the class instead, as in this second example.

With Array in Class

class PxConstant {
    # Static Properties
    static [string] $RegExPathWithWildcard = '\\\*\.\*$|\\\*|\\.\.\*$|\*\.(\?[a-zA-Z0-9\?]{2}|[a-zA-Z0-9\?]\?[a-zA-Z0-9\?]|[a-zA-Z0-9\?]{2}\?)$|\\[^\\]*\.(\?[a-zA-Z0-9\?]{2}|[a-zA-Z0-9\?]\?[a-zA-Z0-9\?]|[a-zA-Z0-9\?]{2}\?)$|\\[^\\]*\.\*$'
}

class PxPath {
    # Properties
    hidden [string[]]$validPathTypes = @('FileSystem_Folder', 'FileSystem_File', 'Registry_Key', 'Registry_Property')
    [string]$Type = $null

    # Constructors
    PxPath ([string]$path) {
        $this.Type = [PxPath]::PathType($path)
    }
    PxPath ([string]$path, [string]$pathType) {
        if ($this.validPathTypes -contains $pathType) {
            $this.Type = $pathType 
        } else {
            Throw "Not a valid path type: $pathType"
        }
    }

    static [String] PathType ([String]$path) {
        [string]$pathType = $null
        if ($path -match [PxConstant]::RegExPathWithWildcard) {
            $pathWithoutWildcard = $path -replace [regex]::escape($matches[0]), ''
            Write-Host $pathWithoutWildcard
        }
        return $pathType
    }
}

$pathType = 'FileSystem_Folders'
$path = try {
    [PxPath]::New("C:\", $pathType)
} catch {
    Write-Host "$($_.Exception.Message)"
}
$path = try {
    [PxPath]::New("\\Server\Folder\*")
} catch {
    Write-Host "$($_.Exception.Message)"
}

I'm wondering if there is a performance or functional argument for one over the other? Or perhaps a strong Best Practice argument in favor? Or is this coders choice really?

\$\endgroup\$
1
\$\begingroup\$

The best argument for using an enum in this context is the ability to:

  1. Early input validation
  2. Allowing users to discover valid inputs

In order to take advantage of that, your first example needs a slight change to use the enum type as the parameter type:

class PxPath {
    PxPath ([string]$path, [pxPathType]$pathType) {
        # if user input a string that doesn't correspond 
        # to a [pxPathType] name, we won't even get this far!
    }
}

Now, your user has the option to pass either a [pxPathType] value or a corresponding string value:

$pxPath = [PxPath]::new("some\path", [pxPathType]::FileSystem_Folder)
# or
$pxPath = [PxPath]::new("some\path", 'FileSystem_Folder')

But this would fail even before we reach inside the constructor:

$pxPath = [PxPath]::new("some\path", 'not_a_valid_enum_name')
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.