Enumeraciones con opciones múltiples

Descripción general:

Apunte que describe la forma de manejar las enumeraciones con opciones múltiples

Ejemplo

Supongamos la siguiente enumeración:


''' <summary>
'''   Sitio donde se escribe el fichero log
''' </summary>
<FlagsAttribute()> _
Public Enum DondeEscriboLogE
    ''' <summary>Valor None</summary>
    None = 0
    ''' <summary>Un fichero de texto estandard</summary>
    FicheroTxt = 1
    ''' <summary>Un fichero XML</summary>
    FicheroXml = 2
    ''' <summary>En una pagina Html</summary>
    FicheroHtml = 4
    ''' <summary>Un fichero con formato CSV</summary>
    FicheroCsv = 8
    ''' <summary>En el registro de eventos de Windows</summary>
    RegistroEventos = 16
End Enum

La enumeración [ DondeEscriboLogE ] está marcada con el atributo [FlagsAttribute] lo quiere decir que se permiten opciones múltiples, por ejemplo


        Dim lugarDondeEscribo As DondeEscriboLogE = 
            DondeEscriboLogE.FicheroTxt Or
            DondeEscriboLogE.FicheroXml Or
            DondeEscriboLogE.RegistroEventos

El problema es diseñar un código que ejecute las diversas opciones cando la opción es múltiple,

La solución es (relativamente) fácil

En primer lugar observa que el siguiente código carga en el [Array] [Values], los valores numéricos de la enumeración, es decir, 1,2,4,8,16


        'Array que contiene los valores numericos de la enumeracion (1,2,4,8,16, etc)
        Dim values As Array = [Enum].GetValues(GetType(DondeEscriboLogE))

[ lugarDondeEscribo ] es la constante enumerada elegida por el usuario ( en este cso tiene un valor multiple)

[ ValorEnumCargadaUser ] es el valor numérico de la enumeración elegida por el usuario, como es multi opción puede tener un valor intermedio .Por ejemplo 18, por ejemplo 3 que corresponde a una opción múltiple [1+2] o por ejemplo 19 [1+2+16]


    Dim ValorEnumCargadaUser As Integer = CType(lugarDondeEscribo, Integer)

El proceso a seguir es el siguiente.

Supongamos que el número de la constante enumerada elegida es 19 (recuerda que los valores numéricos de la enumeración son: 1, 2, 4, 8, 16)

Paso 1) 19>= 16 --> Si ( 16 es una opción a ejecutar) resto 19-16 = 3

Paso 2) 3>= 8 -> No

Paso 3) 3>= 4 -> No

Paso 4) 3>= 2 -> Si ( 2 es una opción a ejecutar) resto 3-2 = 1

Paso 5) 1>= 1 -> Si ( 1 es una opción a ejecutar) resto 1-1 = 0

Paso 6) Valor 0 --> fin del proceso

Observa que se recorren los valores del mayor al menor


      Dim ValorEnumeracion As Integer
        ' iteración de la colección [Values] ( valores numéricos de la enumeración)
        ' se recorre en orden inverso, empezando por la ultima hasta la primera
        For indice As Integer = values.GetUpperBound(0) To
                                values.GetLowerBound(0) Step -1
            ' obtener el valor de la enumeracion ( por ejemplo 16)
            ValorEnumeracion = CType(values.GetValue(indice), Integer)
            'Proceso
            ' vuelta 1)  19 > = 16 -> Si ( 16 es una opción a ejecutar) resto 19 - 16 = 3
            ' vuelta 2)    3 > = 8 -> No
            ' vuelta 3)    3 > = 4 -> No
            ' vuelta 4)    3 > = 2 -> Si  ( 2 es una opción a ejecutar) resto 3 - 2 = 1
            ' vuelta 5)    1 > = 1 -> Si  ( 1 es una opción a ejecutar) resto 1 - 1 = 0
            ' vuelta 6)    Valor 0 ->  fin del proceso
            ' Observa que se recorren los valores del mayor al menor
            If ValorEnumCargadaUser > = ValorEnumeracion Then
                ' HAY que ejecutar la opción de la enumeración cuyo
                ' valor numérico es [ValorEnumeracion]
                ' La interfaz
                Dim objInterfaz As ITraceLog
                ' el valor de la enumeracion que se va a ejecutar
                Dim localConstanteEnumerada As DondeEscriboLogE = CType(ValorEnumeracion, DondeEscriboLogE)
                ' cargar la interfaz con el objeto adecuado
                objInterfaz = BuscaInterfaz(localConstanteEnumerada)
                '
                ' =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =
                ' aquí ejecutar la operación
                objInterfaz.WriteException(ex, type, additionalInfo)
                '
                ‘restar el valor para seguir iterando
                ValorEnumCargadaUser = ValorEnumCargadaUser - ValorEnumeracion
            End If
        Next

La función [] es relativamente sencilla, en función del valor de la constante enumerada devuelve una interfaz cargada con su clase correspondiente.


Private Function BuscaInterfaz(ByVal plugarDondeEscribo As DondeEscriboLogE) As ITraceLog
        Dim objInterfaz As ITraceLog
        Select Case plugarDondeEscribo
            Case DondeEscriboLogE.None
                objInterfaz = New TracelogNull
            Case DondeEscriboLogE.FicheroTxt
                objInterfaz = New TraceLogToFile
            Case DondeEscriboLogE.FicheroXml
                objInterfaz = New TraceLogToXmlWriter
            Case DondeEscriboLogE.FicheroHtml
                objInterfaz = New TracelogNull
            Case DondeEscriboLogE.FicheroCsv
                objInterfaz = New TracelogNull
            Case DondeEscriboLogE.RegistroEventos
                objInterfaz = New TracelogNull
            Case Else
                Throw New NotImplementedException
        End Select
        Return objInterfaz
    End Function

La clase [ TraceLogToFile ] tiene una función [] que se encarga de añadir al fichero log del disco el valor que queremos escribir

Para evitar problemas, he diseñao la clase [ TracelogNull ] que sigue el Patron Null Object , y que tiene el siguiente formato


''' <summary>
'''  Clase traceLog patron Noting
''' </summary>
''' <remarks></remarks>
Public Class TracelogNull
    Implements IDisposable, ITraceLog
    ''' <summary>
    '''   Constructor general
    ''' </summary>
    Public Sub New()
        '
    End Sub
    Public Overloads Sub WriteEntry(ByVal message As String)
                     Implements ITraceLog.WriteEntry
    End Sub
    Public Overloads Sub WriteEntry(ByVal message As String,
                                    ByVal type As TraceEventType)
                     Implements ITraceLog.WriteEntry
    End Sub
    Public Overloads Sub WriteException(ByVal ex As Exception)
                     Implements ITraceLog.WriteException
    End Sub
    Public Overloads Sub WriteException(ByVal ex As Exception,
                                        ByVal additionalInfo As String)
                     Implements ITraceLog.WriteException
    End Sub
    Public Overloads Sub WriteException(ByVal ex As Exception,
                                        ByVal type As TraceEventType)
                     Implements ITraceLog.WriteException
    End Sub
    Public Overloads Sub WriteException(ByVal ex As Exception,
                                        ByVal type As TraceEventType,
                                        ByVal additionalInfo As String)
                     Implements ITraceLog.WriteException
    End Sub
    ' Visual Basic agregó este código para implementar correctamente el patrón descartable.
    Public Sub Dispose() Implements IDisposable.Dispose
        GC.SuppressFinalize(Me)
    End Sub
End Class