HiveBrain v1.2.0
Get Started
← Back to all entries
patternshellMinor

Getting enum values of Pseudo-Enum classes

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
enumgettingclassespseudovalues

Problem

By "Pseudo-Enum" classes I mean cases where someone's used a class with public static properties to emulate enum behaviour; e.g. as described here.

Per the example below, this is useful for classes such as [System.Management.Automation.VerbsCommon], where there is a list of values we're interested in, but no "Get All Values of This Type" method.

I wrote this function for the above type, and it works well for that, but maybe I've missed a trick / there are likely other scenarios that this code could cover which I've not thought of yet.

Clear-Host
function Get-EnumValues {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory,ValueFromPipeline)]
        [Type]$Type
    )
    process {
        if ($Type) {

            Write-Verbose ("Type: {0}" -f $Type.ToString())
            Write-Verbose ("IsEnum? {0}" -f $Type.IsEnum)

            if ($Type.IsEnum) {
                [System.Enum]::GetNames($Type)
            } else {
                #handle pseudo-enums (i.e. for cases where this trick's been used https://stackoverflow.com/a/15713789/361842)
                $Type.GetFields() | ?{$_.IsStatic -and $_.IsPublic} | select -ExpandProperty Name
            }
        } else {
            Write-Verbose ("TypeName is Null")
            $null
        }
    }
}

$t = [type][System.ConsoleColor]
Get-EnumValues $t -Verbose
$t = [type][System.Management.Automation.VerbsCommon]
Get-EnumValues $t -Verbose


Output:

VERBOSE: Type: System.ConsoleColor
VERBOSE: IsEnum? True
Black
DarkBlue
DarkGreen
DarkCyan
DarkRed
DarkMagenta
DarkYellow
Gray
DarkGray
Blue
Green
Cyan
Red
Magenta
Yellow
White
VERBOSE: Type: System.Management.Automation.VerbsCommon
VERBOSE: IsEnum? False
Add
Clear
Close
Copy
Enter
Exit
Find
Format
Get
Hide
Lock
Move
New
Open
Optimize
Push
Pop
Remove
Rename
Reset
Resize
Set
Search
Show
Skip
Step
Join
Redo
Split
Switch
Select
Undo
Unlock
Watch


I'm aware that the shorthand coding style sometimes frowned upon, such as:

`$Type.GetFields() | ?{$_.I

Solution

Let's look for scenarios that this code could cover.

Next 143296.ps1 script, using Get-Type function - Get exported types in the current session

  • Exports all types from all namespaces in the current session to $allTypes, then



  • Selects those with non-empty (pseudo)enumeration to auxiliary Hashtable $ppp and $subTypes.



Script 143296.ps1:

Import-Module -Name Reflection -Force
$allTypes = Get-Type -Force -Namespace * -ErrorAction SilentlyContinue
$allTypes.Count
$ppp=@{}              ### auxiliary Hashtable object, could be useful though
$allTypes | 
    ForEach-Object {
        $aux = $_ | Get-EnumValue -AsFlags
        if ( $aux.Count -ne 0 ) { $ppp.add( $_.FullName, $_.BaseType) }
    }
$ppp.Count 
$subTypes = $allTypes | Where-Object { $ppp.ContainsKey($_.FullName)}
$subTypes.Count
$subGrups = $subtypes | Group-Object -Property BaseType
$subGrups.Count
### make public the most frequent items:
$subGrups | Sort-Object -Property Count -Descending | Select-Object -First 15
                                           


Output:

PS D:\PShell> D:\PShell\CR\143296.ps1
12413
2490
2490
182

Count Name Group
----- ---- -----
1710 System.Enum {System.StringSplitOptions, System.StringComparison, System....
201 System.Object {System.String, System.EventArgs, System.BitConverter, Syste...
58 System.ValueType {System.DateTime, System.DateTimeOffset, System.Boolean, Sys...
53 System.Attribute {System.ComponentModel.BindableAttribute, System.ComponentMo...
28 System.Windows.Freezable {System.Windows.Media.Animation.ThicknessKeyFrame, System.Wi...
24 System.Windows.Framewo... {System.Windows.Shapes.Shape, System.Windows.Controls.Panel,...
22 System.Windows.Control... {Microsoft.VisualStudio.Text.Editor.OutliningMarginHeaderCon...
15 System.Windows.Media.A... {System.Windows.TextDecoration, System.Windows.Media.Animati...
11 System.Windows.Control... {System.Windows.Window, System.Windows.Controls.Primitives.B...
9 System.Windows.Depende... {System.Windows.Navigation.JournalEntry, System.Windows.Cont...
8 System.Globalization.C... {System.Globalization.GregorianCalendar, System.Globalizatio...
8 System.Windows.Control... {System.Windows.Controls.Canvas, System.Windows.Controls.Vir...
7 System.Windows.Media.P... {System.Windows.Media.ArcSegment, System.Windows.Media.Bezie...
7 System.Windows.Control... {System.Windows.Controls.Border, System.Windows.Controls.Ink...
7 System.Windows.Media.G... {System.Windows.Media.CombinedGeometry, System.Windows.Media...


The Get-EnumValue function is explained using Comment-Based Help (CBH):

`Set-StrictMode -Version latest
function Get-EnumValue {
is attributed 'FlagsAttribute' (some [Enum] types)
then output values would be hexadecimal-like strings (8+ hexadecimal ciphers);
otherwise, output values would follow type.
Applies only if -NoValues parameter evaluates to False.

.INPUTS
Valid [type], or a string for the type name.

.OUTPUTS
Always returns [OrderedDictionary] or [system.array] object (see switches).
Never outputs Null; returns an empty (.Count -eq 0) object instead.

.NOTES
If -NoValues evaluates to True, then -AsFlags is ignored.

.EXAMPLE
# Enum, flag enumeration (FlagsAttribute present on object supplied)
[System.AttributeTargets]|Get-EnumValue -AsFlags -Verbose
.EXAMPLE
# Enum, value enumeration (no FlagsAttribute on object supplied)
[System.Runtime.InteropServices.VarEnum]|Get-EnumValue -AsFlags -Verbose
.EXAMPLE
# Struct (not Enum)
[System.Double]|Get-EnumValue -Verbose
.EXAMPLE
# Class (not Enum): useful or at least interesting output
[System.Security.Claims.ClaimValueTypes]|Get-EnumValue -AsFlags | ft -a -Wrap

.REMARKS
Based on 'Get-EnumValues' function and used in answer to:
http://codereview.stackexchange.com/questions/143296/getting-enum-values-of-pseudo-enum-classes
Useful related article: 'Get-Type' - Get exported types in the current session
https://gallery.technet.microsoft.com/scriptcenter/Get-Type-Get-exported-fee19cf7

.FUNCTIONALITY
Tested: Windows 8.1/64bit, Powershell 4
#>
[CmdletBinding(PositionalBinding=$false)]
param (
[Parameter(Mandatory,ValueFromPipeline,Position=0)]$Type,
[parameter(Mandatory=$false)][Switch][bool]$NoValues,
[parameter(Mandatory=$false)][Switch][bool]$AsFlags
)
begin {

Function EnumNoEnum ([type]$noEnumClass) {
$enumFlagsHash = [ordered]@{}
$noEnumClass.GetFields() |
Where-Object {$_.IsStatic -and $_.IsPublic} |
Select-Object -Exp

Code Snippets

Import-Module -Name Reflection -Force
$allTypes = Get-Type -Force -Namespace * -ErrorAction SilentlyContinue
$allTypes.Count
$ppp=@{}              ### auxiliary Hashtable object, could be useful though
$allTypes | 
    ForEach-Object {
        $aux = $_ | Get-EnumValue -AsFlags
        if ( $aux.Count -ne 0 ) { $ppp.add( $_.FullName, $_.BaseType) }
    }
$ppp.Count 
$subTypes = $allTypes | Where-Object { $ppp.ContainsKey($_.FullName)}
$subTypes.Count
$subGrups = $subtypes | Group-Object -Property BaseType
$subGrups.Count
### make public the most frequent items:
$subGrups | Sort-Object -Property Count -Descending | Select-Object -First 15
                                           
<# ### another approach to make public results:
$allBases = $ppp.Keys | %{ "{0,15} {1}" -f ($ppp[$_] | Select -ExpandProperty name), $_ } | sort
$allBases.Count
$subBases = $ppp.Keys | %{ ($ppp[$_] | Select -ExpandProperty name)} | sort -Unique
$subBases.Count
#>

Context

StackExchange Code Review Q#143296, answer score: 2

Revisions (0)

No revisions yet.