Enumerating Strings as bytes? - vb.net

I was looking for a way to enumerate String types in (vb).NET, but .NET enums only accept numeric type values.
The first alternative I came across was to create a dictionary of my enum values and the string I want to return. This worked, but was hard to maintain because if you changed the enum you would have to remember to also change the dictionary.
The second alternative was to set field attributes on each enum member, and retrieve it using reflection. Surely enough this worked aswell and also solved the maintenance problem, but it uses reflection and I've always read that using reflection should be a last resort thing.
So I started thinking and I came up with this: every ASCII character can be represented as a hexadecimal value, and you can assign hexadecimal values to enum members.
You could get rid of the attributes, assign the hexadecimal values to the enum members. Then, when you need the text value, convert the value to a byte array and use System.Text.Encodings.ASCII.GetString(enumMemberBytes) to get the string value.
Now speaking out of experience, anything I come up with is usually either flawed or just plain wrong. What do you guys think about this approach? Is there any reason not to do it like that?
Thanks.
EDIT
As pointed out by David W, enum member values are limited in length, depending on the underlying type (integer by default). So yes, I believe my method works but you are limited to characters in the ASCII table, with a maximum length of 4 or 8 characters using integers or longs respectively.

The easiest way I have found to dynamically parse a String representation of an Enumeration into the actual Enumeration type was to do the following:
Private EnumObject
[Undefined]
ValueA
ValueB
End Enum
dim enumVal as EnumObject = DirectCast([Enum].Parse(GetType(EnumObject), "ValueA"), EnumObject)
This removes the need to maintain a dictionary and allows you to just handle strings instead of converting to an Int or a Long. This does use reflection, but I have not come across any issues as long as you catch and handle any exceptions with the String Parse.

Related

wxWidgets - wxGrid - reading/writing non string cell values

I have a wxGrid to edit an array of numerical data.
I was wondering what's the best way to get non-string data in and out of the cells without going through the string to numeric conversion all the time.
I've used SetCellEditor() to control the data entry.
currently I use this:
// numeric value into cell
str.clear();
str << val1;
m_grid4->SetCellValue(row, col, str);
..
// read value from back into variable
val = atoi(m_grid4->GetCellValue(row, col));
Apart from the fact that atoi() is a bit ugly and a template function with a stringstream would be better, is there a way do get non-string values a bit better in and out of cells?
I was looking at the editors and renderers but can't figure it out.
If you worry about efficiency, you almost certainly should use a custom table class deriving from wxGridTableBase instead of using the default trivial wxGridStringTable implementation which stores everything as strings. Then, and much less importantly, if it makes sense in your case, you can use wxGridCellNumberRenderer which will call your table GetValueAsLong() method instead of GetValue() (which returns a string).
Both of those are demonstrated in wxGrid sample, notably look at BugsGridTable there.
Good luck!

Convert an alphanumeric string to integer format

I need to store an alphanumeric string in an integer column on one of my models.
I have tried:
#result.each do |i|
hex_id = []
i["id"].split(//).each{|c| hex_id.push(c.hex)}
hex_id = hex_id.join
...
Model.create(:origin_id => hex_id)
...
end
When I run this in the console using puts hex_id in place of the create line, it returns the correct values, however the above code results in the origin_id being set to "2147483647" for every instance. An example string input is "t6gnk3pp86gg4sboh5oin5vr40" so that doesn't make any sense to me.
Can anyone tell me what is going wrong here or suggest a better way to store a string like the aforementioned example as a unique integer?
Thanks.
Answering by request form OP
It seems that the hex_id.join operation does not concatenate strings in this case but instead sums or performs binary complement of the hex values. The issue could also be that hex_id is an array of hex-es rather than a string, or char array. Nevertheless, what seems to happen is reaching the maximum positive value for the integer type 2147483647. Still, I was unable to find any documented effects on array.join applied on a hex array, it appears it is not concatenation of the elements.
On the other hand, the desired result 060003008600401100500050040 is too large to be recorded as an integer either. A better approach would be to keep it as a string, or use different algorithm for producing a number form the original string. Perhaps aggregating the hex values by an arithmetic operation will do better than join ?

Equivalent of "Dim As String * 1" VB6 to VB.NET

I have some VB6 code that needs to be migrated to VB.NET, and I wanted to inquire about this line of code, and see if there is a way to implement it in .NET
Dim strChar1 As String * 1
Intellisense keeps telling me that an end of statement is expected.
That's known as a "fixed-length" string. There isn't an exact equivalent in VB.NET.
Edit: Well, OK, there's VBFixedStringAttribute, but I'm pretty sure that exists solely so that automated migration tools can more easily convert VB6 code to VB.NET for you, and it's not really the ".NET way" to do things. Also see the warnings in the article for details on why this still isn't exactly the same thing as a fixed-length string in VB6.
Generally, fixed-length strings are only used in VB6 if you are reading fixed-size records from a file or over the network (i.e. parsing headers in a protocol frame).
For example, you might have a file that contains a set of fixed-length records that all have the format (integer, 1-character-string, double), which you could represent in VB6 as a user-defined type:
Public Type Record
anInteger As Integer
aSingleCharacter As String * 1
aDouble As Double
End Type
This way, VB6 code that reads from the file containing records in this format can read each fixed-sized record stored in the file, and in particular, it will only read 1 byte for aSingleCharacter. Without the * 1, VB6 would have no idea how many characters to read from the file, since a String can normally have any number of characters.
In VB.NET, you can do one of the following, depending on your needs:
If the length matters (i.e. you need to read exactly one byte from some data source, for example) consider using an array instead, such as
Dim aSingleByteArray(1) As Byte
Alternatively, you could use one of the Stream classes. In particular, if you are reading data from a network socket or a file, consider using NetworkStream or FileStream, respectively. A Stream is meant for byte-for-byte access (i.e. raw binary access). StreamReader is a related class that simplifies reading data when it is text-based, so that might be good if you are reading a text file, for example. Otherwise (if dealing with binary data), stick with one of the Stream classes.
If the length doesn't matter, you could just use a "normal" String. That is to say:
Dim aNormalString As String
Which answer is "correct" really depends on why it was declared that way in the original VB6 code.
The fixed length strings has been deprecated in VB.NET because there are several better options.
Since your fixed length string is just one character long, you can use the Char type in this case, as Mark suggested.
Dim strChar1 As Char
Seeing as you're doing a VB6 migration, I'd definitely consider VBFixedStringAttribute as well as the other options listed by Mike Spross, but, in this case, because it is a single character, a Char may be an option in this case too.
As mentioned elsewhere VBFixedString is only acknowledged by the Get and Put VB I/O API. So the best solution (other than rewriting your code that references the "fixed length string") is to write your own equivalent of Microsoft.VisualBasic.Compatibility.VB6.FixedLengthString. See this answer for more details.
VBFixedStringAttribute Class
<VBFixedString(1)> Dim strChar1 As String
ALthough this question was asked ages ago, VB.NET actually has a native fixed-length string -- <VbFixedArray(9)> Public fxdString As Char() 'declare 10-char fixed array. Doing this with scalars actually creates VB6-style Static Arrays.

Is it possible to create custom byte in .net

I am creating a WCF in vb.net inside VS 2010. I have a handful of properties that are currently bytes (0 - 255) and represent different test scores. Is it possible for me to create my own type based on this that will only allow values between 0 and 110? For example, if I have
Dim a as Byte
a = 256
I will get "Constant expression not representable in type 'Byte'." before the code is compiled. I want to have something like this for my own type so the below code would give me "Constant expression not representable in type 'myByte'."
Dim a as myByte
a = 110
You can only use predefined (native) types, as Byte, and implement some features, like overloading operators to check minimum and maximum values. However, not every operator can be overloaded, what, in this case, includes the assignement operator '='.
Check http://msdn.microsoft.com/en-us/library/8edha89s%28v=vs.71%29.aspx and the tutorials if it helps somewhat.
To assign a value tp your type you can make use of properties or methods that set the value checking for boudaries and other conditions, perfectly doable.
But to define it as a native... negative, sir.
Nope, I don't think that's possible. You'll have to use a constructor to initialize your myByte instance and do the range check at runtime (not sure how useful that would be).

When is it necessary to convert data types in Visual Basic 2010

Visual Basic 2010 (Express). I can best give this by example...
If I take a string from a textbox and assign it to an integer variable, I'm under the impression that you're supposed to use CInt to explicitly convert the contents to an integer.
intMyCount = CInt(txtUserInput.Text)
However, if I don't do that, it still seems to work. Similarly, if I have an integer and concatenate it into a label's text property, it still works:
lblResults.Text = intMyCount & " number of times."
rather than using intMyCount.ToString.
Why does it work? Is VB doing implicit conversions when possible? Are there examples where not explicitly converting with .ToString or using CInt would cause unexpected results?
This is done using late-binding, and it's dangerous because if the conversion ever fails (and there's lots of cases where your first example could fail) it ends up in an exception at runtime. To get the compiler to enforce safer casting, turn Option Strict On.
Additionally, most of the time you don't want to use CInt() to convert your string to int. Instead, prefer Integer.Parse() or Integer.TryParse().
Some languages handle string concatenation easily like this for the non-casting to string. Some also handle non-casting to numeric types to do calculations. Some languages don't handle it at all. However as a best-practice, I would always cast the variable to the type you want to avoid issues with improper input types.