Welcome to CrankyGoblin.Com Sign in | Join | Help

Public Class GeoffAppleby

Inherits Microsoft.VisualBasic.MVP : Implements IBrainFart
A Little Enum Tip (the second)

A few weeks ago I wrote a post titled 'A Little Enum Tip'.

In it I discussed mapping some random Integer value into an Enum, after validating that value was an actual member of the Enum in question.

I finished with a nice generic code sample that could handle any enum, including values which map to multiple values in the case of Flags based enums.

I also finished by mentioning that there was a few bugs still in there, asking for volunteers to point them out. There was some discussion on it, most of it fairly obvious.

The worst one that I'd missed (as opposed to left out) was the fact that when I was generating the bitset representing all values defined within a flags Enum, I was using + instead of Or. It's an easy mistake to make, but quite a crucial one. Given that it's so easy to let slip through, I thought I'd give a bit of an explanation on why this was so bad to do - forgive me if I'm preaching to the choir, but I'm sure there's someone out there who might actually find this information useful :)

When defining values for a flags enum, what you're really doing is stating allowable bit masks. The most common way of defining a flags Enum is to use 'powers of two' numbers, either in decimal or hex.

<Flags()> _
Public Enum EnumSample
  None = 0
  FirstValue = 1
  SecondValue = 2
  ThirdValue = 4
  FourthValue = 8
End Enum

But why is this? To really get it, we need to fall down to binary. Here's the five of them:

None 0000
FirstValue 0001
SecondValue 0010
ThirdValue 0100
FourthValue 1000

As you can see, there's only one 1 in any given column. Each column in binary represents a power of two. When two numbers are AND'd together, consider them in binary and keep only the 1s where they appear in the same column on all rows.

FirstValue 0001
AND OtherValue 1111
= 0001

We can only keep the 1 that's in the last column, as it's the only one that appears in both rows. So ANDing one number with a known bitset means that we can discover if that number contains the known bitset very easily. In the above example, (FirstValue AND OtherValue) = FirstValue. So we know we have a match.  But if we redefine OtherValue:

FirstValue 0001
AND OtherValue 1110
= 0000

We now have (FirstValue AND OtherValue) <> FirstValue, so we don't have a match this time.

OR works in a similar way, except that instead of only matching 1s that appear in all rows in a column, we only need to match one.

FirstValue 0001
OR OtherValue 1111
= 1111

FirstValue 0001
OR OtherValue 1110
= 1111

In both cases we ended up with '1111'.

So now, what's the problem with using plus? Plus can lead to some wrong results. If we look at the last sample:

FirstValue 0001
+ OtherValue 1110
= 1111

But for the sample before that:

FirstValue 0001
+ OtherValue 1111
= 10000

Not the same at all now, is it?  0001 AND 10000 does not give us back 0001 anymore.

Poo.

On top of that, we've got a problem with size as well. Not only did the bit sets not match anymore, but we've exploded out of our 4 bit world, into the strange land of 5 bits. On a 32 or 64 bit system, this is not a problem most of the time, but if were running on a 4 bit computer, then we just went boom!

Overflows were the other main bug in the generic solution I wrote in my last post about enums. By using +, i was running the possibility of my flag enum summing code throwing an overflow exception.

But flags Enums always use powers of 2, right? Well, normally, yes. But .net does not enforce it, and there's no reason why you can't for some reason or other. In the first Enum sample I gave at the top, I might choose to coalesce SecondValue and ThirdValue into one UberValue, in which case it would have a value of 6 (0110).

So what else?

Well, in the generic sample I gave on the last post, I was only accepting Int32 values for testing. This is a problem since Enums can actually be defined as Byte, Short, Integer and Long. My sample never allowed Enums value that were larger than Int32.MaxValue to be passed in for testing, so I was locking out all those really large Enums. So I modified my new version to accept Longs as input.

I also discovered (the hard way :) that when you call System.IsDefined(System.Type, SomeNumber), if threw an exception if the underlying type of the Enum (Byte, Short, Integer or Long) did not exactly match the type of the number passed in - which in this case was now always Long.

So I had to use a bit of reflection myself to first vet the underlying type of the Enum, and forcing the value to match.

As result, my sample is a bit more Reflection-heavy than I'd planned - although I've decide that this isn't really an issue. It's very rare that this code will need to be called, so the performance hit is a small price to pay to easily work out if you have a match or not. I particularly don't like all the boxing that is going on, but such is life, I'm too busy to find a better way to improve it right now. (Post note: I just looked. There's actually only two box instructions.)

Here's my (current) end result. Given how I love to tweak and twist, I imagine it'll change again soon as I find performance improvements that I don't have time to actually waste on it :)

  Public Shared Function IsValid(ByVal poType As System.Type, ByVal plValue As Int64) As Boolean

    'we need real data, fool!
    If poType Is Nothing OrElse Not poType.IsEnum Then
      Return False
    End If

    'find the real type of the enum - could Byte, Short, Integer or Long
    Dim oEnumType As System.Type = System.Enum.GetUnderlyingType(poType)
    'box the value passed in, ready for conversion
    Dim oValue As Object = plValue

    'if the enum isn't already long
    If Not oEnumType.Equals(GetType(Int64)) Then
      'check for the type, and make sure value is within the boundaries of allowable values for that type.
      If (oEnumType.Equals(GetType(Int32)) AndAlso (plValue > Int32.MaxValue OrElse plValue < Int32.MinValue)) Then
        Return False
      ElseIf (oEnumType.Equals(GetType(Int16)) AndAlso (plValue > Int16.MaxValue OrElse plValue < Int16.MinValue)) Then
        Return False
      ElseIf (oEnumType.Equals(GetType(Byte)) AndAlso (plValue > Byte.MaxValue OrElse plValue < Byte.MinValue)) Then
        Return False
      End If
      'down convert the value to the right type
      oValue = System.Convert.ChangeType(plValue, oEnumType)
    End If

    Dim bRet As Boolean = System.Enum.IsDefined(poType, oValue)
    If bRet = False Then
      If poType.GetCustomAttributes(GetType(System.FlagsAttribute), False).Length > 0 Then
        Dim lRet As Int64 = MergeValues(poType)
        If (plValue And lRet) = plValue Then
          bRet = True
        End If
      End If
    End If
    Return bRet

  End Function

  Public Shared Function MergeValues(ByVal poType As System.Type) As Int64

    If Not poType.IsEnum Then
      Return 0
    End If

    Dim lRet As Int64 = 0
    For Each lVal As Int64 In System.Enum.GetValues(poType)
      lRet = lRet Or lVal
    Next
    Return lRet
  End Function

Have I missed anything else in here? If so, please let me know :)

Listening to: my poor brain - foo fighters - (3:33)
Posted: Thursday, June 09, 2005 10:23 PM by Geoff Appleby
Filed under: ,

Comments

Public Class GeoffAppleby said:

The work on the next TechEd here in Oz has already started, even though it's still 10 months away. Still,...
# October 21, 2005 8:50 AM

LeVaN said:

http://www.anna-jarphammar-naken.seksi-***.com ^^^ http://www.anna-lenas.seksi-***.com ^^^ http://www.asiatiche-schizzate-di-figa-nella-stanza.str0nz0.com ^^^ http://www.ludicrous-fighette-orale-fotti.str0nz0.com ^^^ http://www.dvd-pollon-20cm.100milfotos.com ^^^ http://www.film-foto-mamadoras.100milfotos.com ^^^ http://www.dilettante-sesso-lesbica.allievo69.com ^^^ http://www.rilasciare-rentboy.allievo69.com ^^^ http://www.kuumempi-tytsyt-humalainen.huor4.com ^^^ http://www.poikkeuksellisen-loistava-koulutytto-nyrkki.huor4.com ^^^ http://www.saikky-sairaanhoitaja-aasi-jotta-kita.hu0ra.com ^^^ http://www.bdsm-clip-free.hu0ra.com ^^^ http://www.farsesco-fighette-gruppo.fott1.com ^^^ http://www.bashful-ragazze-prostituta.fott1.com ^^^ http://www.felicitous-tedesco-anale-fotti.f0tti.com ^^^ http://www.ridiculous-cowgirl-anale-fotti.f0tti.com ^^^ http://www.varuskunta-masturbating.s3ksi.com ^^^ http://www.viilea-loistava-neitsyt.s3ksi.com ^^^ http://www.figlio-francese.ragazza69.com ^^^ http://www.rabbity-pulcino-amore.ragazza69.com ^^^ http://www.carino-giovane-anale-fotti.corneo69.com ^^^ http://www.timorous-soldato-scopata.corneo69.com ^^^ http://www.***-enormi-pompino.dibujitosporn.com ^^^ http://www.gif-cornudovengador.dibujitosporn.com ^^^ http://www.gradito-padre.disponibile69.com ^^^ http://www.sulle-scale-migliore.disponibile69.com ^^^ http://www.famosas-embarazadas-trailer.gayfrei.com ^^^ http://www.culoni-rotondi-clip.gayfrei.com ^^^ http://www.zorras-amateur-film.petarda2fotos.com ^^^ http://www.celeste-hung.petarda2fotos.com ^^^ http://www.xxx-fotos-artisticas.lesbianavideo.com ^^^ http://www.movies-ardientes-con.lesbianavideo.com ^^^ http://www.cuadros-videos-durmiendo.pollonesamateur.com ^^^ http://www.galeria-jovenes-relatos.pollonesamateur.com ^^^ http://www.colegialas-eroticas.sexoexnovia.com ^^^ http://www.culitos-frescos-cuadro.sexoexnovia.com ^^^ http://www.mujeres-argentina-desnudas.latinas-putas.com ^^^ http://www.***-with.latinas-putas.com ^^^ http://www.foto-asiaticas.putasmorochas.com ^^^ http://www.sexo-asco.putasmorochas.com ^^^

# November 28, 2006 1:27 AM

miki said:

http://ristrutturazione-tetto.j95c8-r-1.info/ **#**

http://caldissimo-discreto-madre.h6yzmdsm.info/ **#**

http://senssex-giovane-sex.jzx87ez9h0.info/ **#**

http://intrepido-cameriera-ubriache.keuo0.info/ **#**

http://sexscreto-fighetta-pompino.jpeq50t4gzp.info/ **#**

http://www.j95c8-r-1.info/vetrinista-milano.html **#**

http://www.dgrgajmcwsu.info/nrlighjeo1.html **#**

http://tiger-scarpa.ghkr4icqw.info/ **#**

http://piu-fresco-baciare.jpeq50t4gzp.info/ **#**

http://handsome-cameriera-sexldo.g4sgtrt7hatu.info/ **#**

http://mouse-wireless-optical.jzx87ez9h0.info/ **#**

http://www.mdp4vw4oxcdk.info/infermiera-fotti-a-letto.html **#**

http://www.jkpaip.info/immobile-affitto-milano/ **#**

http://www.bv2x0l2df5r.info/653t4ft.html **#**

http://www.jzx87ez9h0.info/finanziamento-privato-immobiliare.html **#**

http://viaggi-mare-toscana.cde467zt.info/ **#**

http://www.jkpaip.info/bollente-piede.html **#**

http://www.ea2gpm6.info/piu-fresco-buono-padre.html **#**

http://estrazione-perforazione.keuo0.info/ **#**

http://www.bv2x0l2df5r.info/r6gqedn.html **#**

http://www.dgrgajmcwsu.info/jjkvb8e34e4.html **#**

http://il-pompino-perfetto.cde467zt.info/ **#**

http://giovani-ragazze-vid.hlc4w7c48p.info/ **#**

http://www.dgrgajmcwsu.info/neu6pqp.html **#**

http://www.ea2gpm6.info/puglia-bed-breakfast.html **#**

http://immobile-vendita-affitto.g4sgtrt7hatu.info/ **#**

http://avventuroso-toccare.hlc4w7c48p.info/ **#**

http://sexcepire-asiatiche-sexldo.e71fjt8dy.info/ **#**

http://www.ghkr4icqw.info/a5gzzl9lr4.html **#**

http://www.bv2x0l2df5r.info/zz88nor.html **#**

http://www.jkpaip.info/nudo-amatoriale.html **#**

http://adeguato-bionde-strip.dgrgajmcwsu.info/ **#**

http://www.cde467zt.info/fyevhn7.html **#**

http://www.hlc4w7c48p.info/progetto-arredo-ufficio/ **#**

http://affitto-milano-provincia.g4sgtrt7hatu.info/ **#**

http://jessica-rizzo-home-page.cde467zt.info/ **#**

http://manutenzione-imbarcazioni.i5rio48ku.info/ **#**

http://discreto-fighetta-pompino.ghkr4icqw.info/ **#**

http://sex-bbw.g4sgtrt7hatu.info/ **#**

http://www.ea2gpm6.info/puttanelle-che-scopano-gratis.html **#**

http://donne-allupate.gw3x6095.info/ **#**

http://www.g4sgtrt7hatu.info/porno-mulatte/ **#**

http://informatica-umbria.jpeq50t4gzp.info/ **#**

http://www.fj5sm.info/cartuccia-lexmark-e232/ **#**

http://edifici-culto.i5rio48ku.info/ **#**

http://collage-turismo.j95c8-r-1.info/ **#**

http://www.jpeq50t4gzp.info/sql-server-microsoft.html **#**

http://otranto-appartamento-vacanza.gzdfwhf.info/ **#**

http://www.jzx87ez9h0.info/accoglienza-roma/ **#**

# December 29, 2006 11:28 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

To submit your comment, click on these pictures:
  • Geoff's mother on a booger hunt
  • Geoff's bald spot
  • Super Geoff!
Gaptcha Image - No Peeking! Gaptcha Image - No Peeking! Gaptcha Image - No Peeking!
Gaptcha Image - No Peeking! Gaptcha Image - No Peeking! Gaptcha Image - No Peeking!
Gaptcha Image - No Peeking! Gaptcha Image - No Peeking! Gaptcha Image - No Peeking!
Can't recognise the people in these pictures? Look here for a quick introduction.
There's a time limit for you to get your comment submitted before this set of pictures expires. If you think it's been longer than 10 minutes, get some new pictures first (you won't lose what you've typed so far).
Get some new pictures 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS