none
enums with duplicated entries RRS feed

  • General discussion

  • Hey, Scripting Guy!  Why do some public enums have duplicated entries?  That is, within a single enum, two or more entries with the same name and integer value.

    I explored public enums to get a feel for common usage practices.  Found well over a thousand types where both IsPublic and IsEnum.  I do understand that just because something has the Public attribute, that doesn't mean I'm supposed to use it.  I'm just looking, thanks.

        $Assemblies = [AppDomain]::CurrentDomain.GetAssemblies() | where { $_.location -notlike $NULL }
        $AllEnums   = $Assemblies.getexportedtypes() | where { $_.IsPublic -and $_.IsEnum } | sort FullName

    I Examined enums within $AllEnums:

    function Show-Enums( $Enums ) {
        foreach ( $EnumObj in $Enums ) {
            $FullName = $EnumObj.FullName
            "$FullName"
            if ( [enum]::GetUnderlyingType( $FullName ).Name -eq 'uint64' ) {
                [enum]::GetValues( $FullName ) | % {
                    ' {0,15:N0}  {1}' -f [uint64]$_, $_
                }
            } else {
                [enum]::GetValues( $FullName ) | % {
                    ' {0,15:N0}  {1}' -f [int64]$_, $_
                }
            }
        }
    }

    Show-Enums ($AllEnums) > .\temp.txt

    I was able to see that when the designers make the underlying type of an enum to be one of the unsigned types, the values are usually bit masks, and when the underlying type is signed the values are usually (but not always) indexes.  Also, that some underlying types are 32-bit and some are 64-bit (didn't notice any 8- or 16-bit).

    But I did encounter a few dozen instances of what is either an anomaly or a fiendishly clever practice, and so I've come to you for instruction.

    The enums in question have duplicated entries.

    So for example if I call the above function as follows:
        Show-Enums ( [microsoft.powershell.executionpolicy], [windows.messageboximage] )

    The output is:

    Microsoft.PowerShell.ExecutionPolicy
                   0  Unrestricted
                   1  RemoteSigned
                   2  AllSigned
                   3  Restricted
                   3  Restricted
                   4  Bypass
                   5  Undefined
    System.Windows.MessageBoxImage
                   0  None
                  16  Hand
                  16  Hand
                  16  Hand
                  32  Question
                  48  Warning
                  48  Warning
                  64  Asterisk
                  64  Asterisk

    Can you explain what is happening here?  Anomaly or subtlety?

    Here is my complete list of enums with duplicate entries, returned by a script I cobbled together.

    VERBOSE: In [Microsoft.Management.Infrastructure.CimSubscriptionDeliveryType] Push is duplicated
    VERBOSE: In [Microsoft.Management.Infrastructure.Options.CimCallbackMode] Report is duplicated
    VERBOSE: In [Microsoft.Management.Infrastructure.Options.CimPromptType] Normal is duplicated
    VERBOSE: In [Microsoft.Management.Infrastructure.Options.CimResponseType] None is duplicated
    VERBOSE: In [Microsoft.PowerShell.ExecutionPolicy] Restricted is duplicated
    VERBOSE: In [Microsoft.VisualStudio.Text.Differencing.WordSplitBehavior] CharacterClass is duplicated
    VERBOSE: In [Microsoft.WSMan.Management.WSManEnumFlags] WSManFlagHierarchyDeep is duplicated
    VERBOSE: In [System.ComponentModel.Design.SelectionTypes] Normal is duplicated
    VERBOSE: In [System.Diagnostics.Eventing.Reader.StandardEventKeywords] AuditFailure is duplicated
    VERBOSE: In [System.Diagnostics.PerformanceCounterPermissionAccess] Browse is duplicated
    VERBOSE: In [System.Diagnostics.Tracing.EventKeywords] WdiContext is duplicated
    VERBOSE: In [System.DirectoryServices.AuthenticationTypes] SecureSocketsLayer is duplicated
    VERBOSE: In [System.Drawing.Drawing2D.HatchStyle] Horizontal is duplicated
    VERBOSE: In [System.Drawing.Drawing2D.PathPointType] Bezier3 is duplicated
    VERBOSE: In [System.Drawing.Imaging.EmfPlusRecordType] EmfMin is duplicated
    VERBOSE: In [System.Drawing.Imaging.PixelFormat] DontCare is duplicated
    VERBOSE: In [System.Drawing.RotateFlipType] RotateNoneFlipNone is duplicated
    VERBOSE: In [System.LoaderOptimization] DomainMask is duplicated
    VERBOSE: In [System.Management.Automation.DSCResourceRunAsCredential] Default is duplicated
    VERBOSE: In [System.Management.Automation.Language.TokenFlags] BinaryPrecedenceMask is duplicated
    VERBOSE: In [System.Management.Automation.PSCredentialUIOptions] Default is duplicated
    VERBOSE: In [System.Management.Automation.SigningOption] AddFullCertificateChainExceptRoot is duplicated
    VERBOSE: In [System.Net.HttpStatusCode] MultipleChoices is duplicated
    VERBOSE: In [System.Net.NetworkInformation.IPStatus] DestinationProhibited is duplicated
    VERBOSE: In [System.Net.Sockets.AddressFamily] NS is duplicated
    VERBOSE: In [System.Net.Sockets.ProtocolFamily] NS is duplicated
    VERBOSE: In [System.Net.Sockets.ProtocolType] Unspecified is duplicated
    VERBOSE: In [System.Net.Sockets.SocketOptionName] Debug is duplicated
    VERBOSE: In [System.Net.TransportType] Udp is duplicated
    VERBOSE: In [System.Reflection.EventAttributes] RTSpecialName is duplicated
    VERBOSE: In [System.Reflection.MethodAttributes] ReuseSlot is duplicated
    VERBOSE: In [System.Reflection.MethodImplAttributes] IL is duplicated
    VERBOSE: In [System.Reflection.TypeAttributes] NotPublic is duplicated
    VERBOSE: In [System.Runtime.InteropServices.CALLCONV] CC_MSCPASCAL is duplicated
    VERBOSE: In [System.Runtime.InteropServices.ComTypes.CALLCONV] CC_MSCPASCAL is duplicated
    VERBOSE: In [System.Security.AccessControl.AceType] SystemAlarmCallbackObject is duplicated
    VERBOSE: In [System.Security.AccessControl.FileSystemRights] ReadData is duplicated
    VERBOSE: In [System.Security.AccessControl.RegistryRights] ReadKey is duplicated
    VERBOSE: In [System.Security.Cryptography.CngKeyOpenOptions] None is duplicated
    VERBOSE: In [System.Security.Cryptography.X509Certificates.X509ContentType] Pfx is duplicated
    VERBOSE: In [System.Security.Principal.WellKnownSidType] WinBuiltinTerminalServerLicenseServersSid is duplicated
    VERBOSE: In [System.Windows.Forms.AccessibleStates] Mixed is duplicated
    VERBOSE: In [System.Windows.Forms.ArrangeDirection] Left is duplicated
    VERBOSE: In [System.Windows.Forms.Keys] Return is duplicated
    VERBOSE: In [System.Windows.Forms.MenuGlyph] Arrow is duplicated
    VERBOSE: In [System.Windows.Forms.MessageBoxIcon] Hand is duplicated
    VERBOSE: In [System.Windows.Forms.ScrollButton] Min is duplicated
    VERBOSE: In [System.Windows.Forms.TextFormatFlags] GlyphOverhangPadding is duplicated
    VERBOSE: In [System.Windows.Input.Key] Return is duplicated
    VERBOSE: In [System.Windows.Media.BitmapScalingMode] Linear is duplicated
    VERBOSE: In [System.Windows.Media.Imaging.BitmapCacheOption] OnDemand is duplicated
    VERBOSE: In [System.Windows.MessageBoxImage] Hand is duplicated
    VERBOSE: In [System.Xml.XPath.XPathResultType] String is duplicated
    VERBOSE: In [Windows.UI.Notifications.TileTemplateType] TileSquare150x150Image is duplicated

    Tuesday, October 18, 2016 3:22 PM

All replies

  • Why does it matter? What will you do with the answer if you find one?

    -- Bill Stewart [Bill_Stewart]

    Tuesday, October 18, 2016 3:43 PM
    Moderator
  • Hi,

    in your first example, Restricted is the Default value. In some cases, multiple text representations may have the same logical meaning. In this case, you can simply give the same numerical value, making the low-level processing simpler.

    When looking up the names for the values, it appears to start by the numbers and select the first string representation. This results in having "restricted" listed twice.

    Can't say about the second enumeration, didn't have the assembly loaded and couldn't be bothered to look up just which one it was I needed to load.

    Cheers,
    Fred


    There's no place like 127.0.0.1

    Tuesday, October 18, 2016 3:59 PM
  • Right, there are different names for the same values. Looking up the enum definition shows that:

    namespace Microsoft.PowerShell
    {
        public enum ExecutionPolicy
        {
            Unrestricted = 0,
            RemoteSigned = 1,
            AllSigned = 2,
            Restricted = 3,
            Default = 3,
            Bypass = 4,
            Undefined = 5
        }
    }


    -Raimund

    Tuesday, October 18, 2016 5:28 PM
  • The helpful replies from Fred and Raimund led me to understand what's happening.

    Moderator Bill's inappropriately dismissive reply missed seeing a usage misunderstanding of mine that might be instructive to others.

    Class [enum] has static methods GetNames and GetValues.  When called with the ubiquitous example [DayOfWeek] they appear to return identical arrays of seven weekday names (although one is an array of simple strings while the other is an array of objects).  But this does not necessarily happen for every enum.  Although every enum has unique names, in some enums multiple names have the same value.  My script snippet used GetValues and should more usefully have used GetNames.

    For example, with [Windows.MessageBoxImage], the .NET Framework documentation of the enumeration in the System.Windows Namespace shows nine unique member names, and they are indeed the very same ones returned in PowerShell by [enum]::GetNames([Windows.MessageBoxImage]).  The GetValues method also returns nine names, but not unique, because some of the names have been aliased to each other.

    There's a minor gotcha, of course.  GetValues returns an array of objects, each of which, conveniently, has a Name and a Value, while GetNames returns just an array of strings.  This, plus thinking they were otherwise identical because of the [DayOfWeek] example, led me to choose GetValues over GetNames.  In a Where-Object iteration over GetValues you can get the Name with $_ and the Value with [int32]$_, but in a Where-Object iteration over GetNames the Name is $_ but the Value is [ClassName]::$_.ToInt32($Null).

    Bottom line: No anomaly and no fiendishly clever practice going on here.  Use [enum]::GetNames to get all of an enum's member names.

    -John
    Tuesday, October 18, 2016 10:14 PM
  • Wednesday, October 19, 2016 2:25 PM
    Moderator