How do I test if an enum is contained in a number? - vb.net

In VB6 I combine several DT_DRAW_FLAG values like this:
dim lMyFlags As DT_DRAW_FLAG
lMyFlags = DT_CENTER OR DT_VCENTER OR DT_RTLREADING
This would result in lMyFlags = 131077
Now to test if a certain flag is contained in such a combine flags value, I would do the following:
If (131077 And DT_RTLREADING) = DT_RTLREADING Then
'DT_RTLREADING is contained.
Else
'DT_RTLREADING is NOT contained.
End Enum
How would I do this in VB.NET?
Do I still have to use this "pure math" approach, or is there a method like...
lMyFlags.ContainsEnum(DT_RTLREADING)
... which I have not found yet?
Thank you!

If you have an enum declaration like this
<Flags()> Public Enum DT_DRAW_FLAG As Integer
DT_CENTER = 1
DT_VCENTER = 2
DT_RTLREADING = 4
End Enum
Then you can use HasFlag to do your logic
Dim lMyFlags As DT_DRAW_FLAG = DT_DRAW_FLAG.DT_CENTER Or DT_DRAW_FLAG.DT_RTLREADING
lMyFlags.HasFlag(DT_DRAW_FLAG.DT_RTLREADING) ' => true
The important point here is that the single enum values are powers of two.

Accepted answer is good, it works. In your case, your Enum might already have the flags attribute, because it is a combination of three powers of 2: 2^0=1, 2^2=4, and 2^17=131072
Your enum may look like this
<Flags>
Public Enum DT_DRAW_FLAG As Long
''' <summary>
''' 2 ^ 0
''' </summary>
DT_CENTER = 1
' 2 ^ 1 in here
''' <summary>
''' 2 ^ 4
''' </summary>
DT_VCENTER = 4
' 2 ^ 3 through 2 ^ 16 in here
''' <summary>
''' 2 ^ 17
''' </summary>
DT_RTLREADING = 131072
End Enum
The Flags Attribute
Indicates that an enumeration can be treated as a bit field; that is, a set of flags.
However, whether or not it has the Flags attribute, you can treat it the same way using bitwise And. I believe the HasFlags function is just shorthand for the bitwise logic:
' Bitwise logic
If (lMyFlags And DT_DRAW_FLAG.DT_RTLREADING) = DT_DRAW_FLAG.DT_RTLREADING Then
' Reading is contained
Else
' Reading is not contained
End If
' HasFlags
If lMyFlags.HasFlag(DT_DRAW_FLAG.DT_RTLREADING) Then
' Reading is contained
Else
' Reading is not contained
End If
It is certainly less code.
Note, you don't combine enums in the way that you have shown, without some additional conversion. Use bitwise Or to do that
Dim lMyFlags = DT_DRAW_FLAG.DT_CENTER Or DT_DRAW_FLAG.DT_VCENTER Or DT_DRAW_FLAG.DT_RTLREADING
Also, you can use Enum.HasFlag regardless of whether you used the Flags Attribute. As far as I know, the attribute is just used to signal to the consumer that the values are distinct powers of two, and bitwise logic can be performed on them. There is nothing strictly going on with the flags attribute so there's some trust in the consumer to know what to do with it (and we assume the original author knew about it, too)

Related

How to find every combination of a binary 16 digit number

I have 16 different options in my program and i have a 16 character variable which is filled with 1's or 0's depending on the options that are selected (0000000000000000 means nothing is selected, 0010101010000101 means options 3,5,7,9,14 and 16 are selected, 1111111111111111 means everything is selected.)
When i run my program, the code looks (using an if statement) for a 1 in the designated character of the 16 digit number and if there is one there then it runs the code for that option, otherwise it skips it..
e.g option 3 looks too see if the 3rd character (0010000000000000) is a 1 and if it is it runs the code.
Now what i am trying to do is generate a list of every different combination that is possible so I can create an option for it to just loop through and run every possible option:
0000000000000001
0000000000000010
0000000000000011
...
1111111111111100
1111111111111110
1111111111111111
I have tried this but i think it may take a couple of years to run jaja:
Dim binString As String
Dim binNUM As Decimal = "0.0000000000000001"
Do Until binNUM = 0.11111111111111111
binString = binNUM.ToString
If binString.Contains(1) Then
If binString.Contains(2) Or binString.Contains(3) Or binString.Contains(4) Or binString.Contains(5) Or binString.Contains(6) Or binString.Contains(7) Or binString.Contains(8) Or binString.Contains(9) Then
Else
Debug.Print(binNUM)
End If
End If
binNUM = binNUM + 0.0000000000000001
After the code above is complete i would then take the output list and remove any instances of "0." and then any lines which had fewer than 16 chararcters (because the final character would be a 0 and not show) I would add a 0 until there was 16 characters. I know this bit might be stupid but its as far a ive got
Is there a faster way I can I generate a list like this in VB.net?
You should be able to get the list by using Convert.ToString as follows:
Dim sb As New System.Text.StringBuilder
For i As Integer = 0 To 65535
sb.AppendLine(Convert.ToString(i, 2).PadLeft(16, "0"c))
Next
Debug.Print(sb.ToString())
BTW: This should finish in under one second, depending on your system ;-)
Create an enum with FlagAttributes, which allows you to do the key functions you list. Here is an example of setting it up in a small project I am working on:
<FlagsAttribute>
Public Enum MyFlags As Integer
None = 0
One = 1
Two = 2
Three = 4
Four = 8
Five = 16
Recon = 32
Saboteur = 64
Mine = 128
Headquarters = 256
End Enum
e.g.
Dim temp as MyFlags
Dim doesIt as Boolean
temp = MyFlags.One
doesIt = temp.HasFlag(MyFlags.Two)
temp = temp OR MyFlags.Three
'etc.
The real advantage is how it prints out, if you want something other than 0, 1 and is much more human friendly.

Add one to an xsl variable if there are one or more matching elements

I'm working on an xsl transform that is creating item numbers. It includes statements like this:
data-item-no="{$itemOffset + count(list//para)}"
This is fine when I want to add the number of para elements to $itemOffset, but in this case the paras are all rolled up into a single item. I want to add 0 if there are no matches for "list//para" and 1 if there is one or more "list//para". How can I do this in xsl?
In XSLT 2.0 you can make it explicit with
$itemOffset + (if (list//para) then 1 else 0)
In XSLT 1.0 make use of the fact that
an empty node set coerces to boolean false
a non-empty node set coerces to boolean true
boolean false coerces to the number 0
boolean true coerces to the number 1
So:
$itemOffset + boolean(list//para)
(the + operator implicitly coerces its arguments to be numbers)

Which is correct - '+' or '|' in objective-c?

I've seen both of these notations in various threads and I'd like to know which is correct?
Or, is there no functional difference?
return UIInterfaceOrientationMaskPortrait + UIInterfaceOrientationMaskPortraitUpsideDown;
or
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
As others have stated, | is the correct operator to use for bitfields.
While other operators might work and yield similar results it is semantically wrong to use them and confusing for other programmers reading your code.
Using + (or ^ which has a similar effect in this case) just obfuscates the meaning. In a code review I would reject it.
The '|' is better
For the purpose of combining bit mask flags, they are almost the same. You have:
0 + 0 = 0
0 | 0 = 0
0 + 1 = 1
0 | 1 = 1
1 + 0 = 1
1 | 0 = 1
However, they are different when you do:
1 + 1 = 0 // and 1 goes to higher bit
1 | 1 = 1
You can have a '1 + 1' case, when you combine same flags. It can happen by mistake, when you modify existing mask, or when you do something less trivial, say you get those flags by calling other methods, then you accumulate them in some variable, and it is possible to get the same flag several times.
In this case, only | gives correct results, so I say that it is better to get a habit of always using |.
It would also make your code more readable by others.
They are both have the same result in this particular case, but | is preferred because it's a more correct operator for bitfields where arithmetic is possible but usually meaningless.
For example, if you have the interface orientation in a variable and you want to enable or disable a particular value, using + can lead to unexpected behavior.
UIInterfaceOrientationMask mask = UIInterfaceOrientationMaskPortrait;
// some other code ...
// Now I want to (incorrectly!) enable portrait, without checking it first
mask = mask + UIInterfaceOrientationMaskPortrait;
// mask now counterintuitively == UIInterfaceOrientationMaskPortraitUpsideDown
If instead you user |, you can ensure that you are operating correctly on the bit field:
UIInterfaceOrientationMask mask = UIInterfaceOrientationMaskPortrait;
// ...
// Now I want to (correctly!) enable portrait, without checking it first
mask = mask | UIInterfaceOrientationMaskPortrait; // mask is what you would expect it to be.

VB.Net Enum ToString returns an unknown number

I built a simple vb.net winforms project that pings IP addresses and logs the results. It works fine on most machines I've tried it on. I log the status result of the ping (System.Net.NetworkInformation.IPStatus) by using the IPStatus.tostring method.
Normally this returns a text result such as "Success" or "TimedOut"
Yesterday, on one machine it returned "65" ...which is not one of the enum values. I have a feeling it might be a combination of values. I ran some test code:
Dim status As System.Net.NetworkInformation.IPStatus
status = Net.NetworkInformation.IPStatus.Success
MsgBox(status.ToString)
Which returns "Success"
And this:
status = Net.NetworkInformation.IPStatus.BadDestination Or Net.NetworkInformation.IPStatus.BadHeader
MsgBox(status.ToString)
Which returns "11050"
I suspect the "65" I saw was the result of some combination of enum values. Is there any way I can change the code in my second example to show the text names of both values? That is... any way I can see ALL values in this variable?
IPStatus is NOT a Flags enum, therefore it is not appropriate to combine its member values in this way. This is its definition via Reflector:
Public Enum IPStatus
' Fields
BadDestination = &H2B0A
BadHeader = &H2B22
BadOption = &H2AFF
BadRoute = &H2B04
DestinationHostUnreachable = &H2AFB
DestinationNetworkUnreachable = &H2AFA
DestinationPortUnreachable = &H2AFD
DestinationProhibited = &H2AFC
DestinationProtocolUnreachable = &H2AFC
DestinationScopeMismatch = &H2B25
DestinationUnreachable = &H2B20
HardwareError = &H2B00
IcmpError = &H2B24
NoResources = &H2AFE
PacketTooBig = &H2B01
ParameterProblem = &H2B07
SourceQuench = &H2B08
Success = 0
TimedOut = &H2B02
TimeExceeded = &H2B21
TtlExpired = &H2B05
TtlReassemblyTimeExceeded = &H2B06
Unknown = -1
UnrecognizedNextHeader = &H2B23
End Enum
How you are getting an IPStatus value of 65 - now that's the real question :)
Try using System.Enum to get the name of the value.
In your example, use:
MsgBox(System.Enum.GetName(GetType(Net.NetworkInformation.IPStatus), status))
It looks like apart from Success (0) and Unknown (-1), the defined enum values range from 11002 to 11045, so 65 is not a combination of any of the defined enum values.
If you are getting 65 back, you will not be able to resolve this to a string.
That enum is not marked with the FlagsAttribute and therefore should not be or'd together because the result could overlap. You are better off creating your own enum to contain the values you are looking for.
You should be able to loop over the enum's range using something like [1], test whether the current enum bit is represented in the value and add it to a string builder.
I find it hard to write up a working sample in VB.NET in this little text box, but I'm sure someone else will oblige.
[1] http://damieng.com/blog/2008/04/10/using-linq-to-foreach-over-an-enum-in-c

Best Way To Find Pattern 6 digit space 7 digit ###### ####### with VB.NET

Parsing a text file in vb.net and need to locate the latitude and longitude in these two sections of text. The patter is 6 digits space 7 digits (364800 0953600). The samples are from two different map files and have slightly differing formats.
I 2H02 364800 0953600 ' SEC72 10496300-
I 2H05 360100 0953645 ' ZFW J602 ZME 2A93 10496400-
I 2H06 361215 0952400 ' SEC72 ZME 2A75 10496500-
I 2H07 361715 0951145 ' SEC27/72 ZME 2A78 10496600-
I 2H08 362025 0950100 ' TUL ZME 2A69 10496700-
I 2H10 360800 0952915 ' ZME 2A85 10496800-
I 2H11 362500 0955015 ' SEC62/72 10496900-
I 2H14 364145 0954315 ' TUL 10497000-
I A85A 'AL851 50591 REF 33393944
391500 0831100 ' 50591 REF 33393945
I A85B 'AL851 50591 REF 33393946
374500 0825700 ' 50591 REF 33393947
I A87A 'AL871 111592 REF 33393948
402050 0814420 ' 111592 REF 33393949
I A87B 'AL871 111592 REF 33393950
400449 0814400 ' 111592 REF 33393951
I A87C 'AL872 '030394 GDK 33393952
392000 0810000 ' '030394 GDK 33393953
Thanks,
Dave
Dim matches As MatchCollection
Dim regex As New Regex("\d{6} \d{7}")
matches = regex.Matches(your_text_string)
A simple regex should do it:
[0-9]{6} [0-9]{7}
.....
(?<First>\d{6})\s(?<Second>\d{7})
Do a simple group capture. It appears your RegEx formula will be simple enough to handle both scenarios (be a little lose on the space detection). Then you can access the group properties of the match (either named or just basic index) and get the data you need.