[RESOLVED] Method for conversion, can it be improved?
Hey!
We have a situation where we are using data from a service that is from a non normalized database. In this particular case we are trying to create information to a graph component on what axis to draw and what units. One axix can be displayed with two different units (us and SI) This information is stored in the database as an integer where 1 = SI, 2=US and 12 or 21 is both. Unit is an enum with SI, US or BothSIAndUS
This small method is what we have dreamt up so far
Code:
Private Function GetUnitFromInteger(unitsforAxis As Integer) As Unit
Dim ints = unitsforAxis.ToString.ToArray().Distinct()
If ints.Count = 2 Then
Return Unit.BothSIAndUS
ElseIf ints.Count = 1 Then
If ints.First() = "1" Then
Return Unit.SI
ElseIf ints.First() = "2" Then
Return Unit.US
Else
Throw New NotImplementedException("There is no support for unit: " & ints.First())
End If
Else
Throw New Exception("The integer can either be 1, 2 or 12, or 21")
End If
End Function
The code feels kind of crappy. Is there a better more clean way to parse information of this kind? The code does work but ther are lots of Ifs and magic numbers.
We have 10 more kinds of similar data where many settings have been cramped into a single integer or string that needs to be splitted into proper objects. We try to do this as close to the db as possible to avoid lots of string parsing in our services or viewmodels.
this is a really old database, and for now we only support 1, 2, 12, 21, everything else is supposed to throw an exception and the users have to fix it manually.
/H
Re: Method for conversion, can it be improved?
Assuming that 'Unit' is an Enum defined something like that shown below:
Code:
Enum Unit
Undefined = 0
SI = 1
US = 2
BothSIAndUS = 21
End Enum
Private Function GetUnitFromInteger(unitsforAxis As Integer) As Unit
Dim ret As Unit = Unit.Undefined
If [Enum].IsDefined(GetType(Unit), unitsforAxis) Then
ret = CType(unitsforAxis, Unit)
End If
Return ret
End Function
Re: Method for conversion, can it be improved?
Quote:
1 = SI, 2=US and 12 or 21 is both
Are you in a position to change the way those values are stored in the DB. If so a more usual way of handling situations where more than one flag can be true is to use bitwise operations.
So SI = 1, US = 2. If you had a third state you'd assign it to 4, a fourth state would be 8 and so on.
If you think what that looks like in binary you get:-
SI = 0001
US = 0010
3rd state = 0100
4th state = 1000
This is handy because you can now store any combination of flags, so SI and US = 0011 (or 3). US and 4th state = 1010 (or 10).
In the client you can store those integer value as an enum:-
Code:
Enum UnitType
SI = 1
US = 2
3rdState = 4
4thState = 8
end Enum
...which will make mapping the client to the database much simpler.
Finally you can now use ANDs and ORs on the value to add or remove flags and to check whether a particular flag is set (not in a position to check this in VB.Net but this works in C# so the syntax will be similar):-
Code:
//set a single a flag on
MyState |= UnitType.US
//Set a couple of flags on
MyState |= Unittype.SI | UnitType.US
//Check if a given flag is on
bool UseSIOnAxis = (MyState & UnitType.SI == UnitType.SI )
//Set a flag off
Mystate &= ~UnitType.SI //~ is the negative of a bit string - not sure what that looks like in VB.
Re: Method for conversion, can it be improved?
Code:
<Flags> _
Enum Unit As Integer
Undefined = 0
SI = 1 << 1
US = 1 << 2
BothSIAndUS = Unit.SI Or Unit.US
End Enum
Private Sub UnitDecode(aUnit As Unit)
If aUnit = Unit.BothSIAndUS Then
ElseIf aUnit = Unit.SI Then
ElseIf aUnit = Unit.US Then
End If
End Sub
Re: Method for conversion, can it be improved?
Thanks for your suggestions. Yes one idea is definetly to use binaries in the database, but it is a legacy db from the 80's that has been moved intoa sql server, and lots of other systems depend on it, so for now we need to do some kind of conversion.
Always great to learn how to write smarter code!
Thanks!
/H
Re: [RESOLVED] Method for conversion, can it be improved?
although i would go with funky's suggestion and update the database field and combine this with dbasnett's enum i do not see anything wrong with a straight forward code if you want to leave the db untouched. you say you only have 1, 2, 12 and 21 right?
Code:
Private Function GetUnitFromInteger(unitsforAxis As Integer) As Unit
Select Case unitsforAxis
Case 1
Return Unit.SI
Case 2
Return Unit.US
Case 12, 21
Return unit.BothSIAndUS
Case Else
Throw New ArgumentException("The integer can either be 1, 2 or 12, or 21")
End Select
End Function
how did you come to cast the int to a string, split it into chars aso?
edit: ahh.. i think i now know. you are also dealing with values like 12112 right? hmm...