Casting an Integer to a Single, preserving bit representation - vb.net

Is there a fast way in VB.NET to take a 32-bit int and cast to a 32-bit float while preserving the underlying bit structure? BitConverter will do this, but I'd like to cast it directly without involving byte arrays.

Damn, how could I possibly forget about The C-style Union?
<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Explicit)> _
Public Structure IntFloatUnion
<Runtime.InteropServices.FieldOffset(0)> Public i As Integer
<Runtime.InteropServices.FieldOffset(0)> Public f As Single
End Structure
Sub Main()
Dim u As IntFloatUnion
u.i = 42
Console.WriteLine(u.f)
Console.ReadLine()
End Sub
Well, how about writing a helper function in C# similar to one shown here:
public static class FancyConverter
{
public static unsafe float FloatFromBytes(int i)
{
return *((float*)(void*)(&i));
}
}
This can be compiled to a separate dll and referenced from the VB project.

Related

How to construct single character constants

How do I define a constant Char value, similar to vbCr? This does not work...
Public Const ctrM As Char = "\m"C
This says the constant must have exactly one character. Well, ok, isn't that what "\m" is?, what about the following
Public Const ctrM as Char = Convert.ToChar(9)
That's not allowed because it's a function. Huh. Luckily this does work:
Public Dim ctrM as Char = Convert.ToChar(9)
But this seems sub-optimal. Am I missing something here?
The answer by fsintegral is fine, but can be slightly simpler. And you can use the Framework functions if you prefer them to the VB Functions.
Class method:
Public Class AppConsts
Public Shared ReadOnly CtrlEM As Char = Convert.ToChar(25)
Public Shared ReadOnly CtrlT As Char = Convert.ToChar(9)
Public Shared ReadOnly CtrlN As Char = Convert.ToChar(10)
Public Shared ReadOnly CtrlM As Char = Convert.ToChar(13)
Public Shared ReadOnly CrLf As String = CtrlN & CtrlM
...
End Class
'Usage:
Dim s as string = "..." & AppConts.CtrlEM
They will even show up in intellisense. If you dont like the Type/Class name intruding, you can import the class (I kind of like the Type portion included because it narrows the IntelliSense list rapidly to the relevant values):
Imports AppConsts
....
Dim s As String = CtrlEM
Alternatively, you can use the module method:
Module Program
Friend ReadOnly CtrlM As Char = Convert.ToChar(25)
End Module
' usage:
Dim s2 As String = "xxxx..." & CtrlM
They are not really constants as far as how the compiler treats them at compile time because they aren't -- they are just ReadOnly fields. But as far as your code is concerned in the IDE, they will act, feel and taste like constants.
It is the use of Const statement which limits how you can define them and require you to use (some) the VB functions rather than .NET ones.
Replace:
Public Const ctrM as Char = "\m"C
for this:
Public Const ctrM As Char = "m"c
Credits goes to Plutonix for giving a working/workable solution in a comment.
Used the following approach when I made large use of Modules long ago.
Add a Public Module to your Project :
Public Module MyConsts
' Define your constant Char
Public Const vbTabC As Char = Microsoft.VisualBasic.Chr(9) ' For Tabulation
Public Const vbEMC As Char = Microsoft.VisualBasic.Chr(25) ' For EM (End of Medium)
' ^^ if you know the ASCII Char Code.
' Use Microsoft.VisualBasic.ChrW() for Unicode (unsure of that)
Public Const vbCharQM As Char = "?"c
Public Const vbComma As Char = ","c
Public Const vbDot As Char = "."c
' or
Public Const vbCharQM2 As Char = CChar("?")
' ^^ if you can actually write the char as String in the Compiler IDE
End Module
Then use the constants identifier anywhere in your project like any VB constant string, but, they are of type Char of course (To combine them with String, you'll have to use .ToString())
Public Sub TestConstChar()
MessageBox.Show("[" + vbEMC.ToString() + "]")
' But hey ! What's the purpose of using End of Medium Char ?
End sub
Note that you have Environment.NewLine that automatically returns the valid Line Feed, or Carriage Return/Line Feed, or only Carriage Return, or even another control Char/String/Stream that is on use on your Operating System.
Based on the Environment.NewLine example, you can also define a (wandering) Class
Public Class MyConstChars
Public Shared ReadOnly Property Tab() As Char
Get
Return Microsoft.VisualBasic.ControlChars.Tab
End Get
End Property
' ...
End Class
' And use it anywhere like myString = "1" + MyConstChars.Tab.ToString() + "One"
This approach allows you to have more control over the actual value of the static/shared Property, like with Environment.NewLine, and allows your Class to propose much more options (Members) than a simple Constant. However, writing the LambdaClassName.LambdaClassProperty isn't very intuitive I reckon.
One another way to ease coding by using constant tags/identifiers in the IDE is to define Code Templates. A code template (piece of code) can be defined in the options of your IDE. You may already know what it is about : you type a keyword, then the IDE replace that keyword with one block of code (that you use often enough to require that shortcut) That's what is happening when you redefines (Overrides) a .ToString() Function in classes.
' I have for example one code template keyword...
PlaceholderChecker
' ...that generates the following Code :
#If IsDebugMode Then
''' <summary>
''' Placeholder Routine to check wether ALL Class Components are included in Solution.
''' </summary>
Private Shared Sub PlaceholderChecker()
p_ClassVariableName_ClassPartialSuffix = True
End Sub
#End If
In some cases, you don't have to define constants - or have to write more complex code - to get where you want.

vb.net - creating array/list from loaded interfaces

I'm having trouble creating a global array that i can use in other functions.
I have this code right under "Public Class myClass":
Dim LoadedPlugins As Array
Then in a function I have this:
Dim PluginList As String() = Directory.GetFiles(appDir, "*.dll")
For Each Plugin As String In PluginList
Dim Asm As Assembly
Dim SysTypes As System.Type
Asm = Assembly.LoadFrom(Plugin)
SysTypes = Asm.GetType(Asm.GetName.Name + ".frmMain")
Dim IsForm As Boolean = GetType(Form).IsAssignableFrom(SysTypes)
If IsForm Then
Dim tmpPlugin As PluginAPI = CType(Activator.CreateInstance(SysTypes), PluginAPI)
LoadedPlugins(count) = tmpPlugin
In the Interface file I have:
Public Interface PluginAPI
Function PluginTitle() As String
Function PluginVersion() As String
Function CustomFunction() As Boolean
End Interface
Now obviously that doesn't work, how can I add the tmpPlugin to an array or list so I can use it in other functions?
The main thing I need to be able to do is loop through all the loaded plugins and execute the CustomFunction in a separate function than the one that loads the plugins listed above.
Can anyone help me?
Use this for your dim:
Public Shared LoadedPlugins As Array
However I notice a few things
Some tips to make writing programs faster (in the end, but more thinking for design):
use Option Strict.
give LoadedPlugins a type (PluginAPI)
use a generic list instead of array
don't use globals. Figure out a way to give this info to the classes that need it
this is a bit of an art. But don't give up - 5 programs later you will have it down!

Integer.TryParse - a better way?

I find myself often needing to use Integer.TryParse to test if a value is an integer. However, when you use TryParse, you have to pass a reference variable to the function, so I find myself always needing to create a blank integer to pass in. Usually it looks something like:
Dim tempInt as Integer
If Integer.TryParse(myInt, tempInt) Then
I find this to be quite cumbersome considering that all I want is a simple True / False response. Is there a better way to approach this? Why isn't there an overloaded function where I can just pass the value I want to test and get a true / false response?
No need to declare the integer.
If Integer.TryParse(intToCheck, 0) Then
or
If Integer.TryParse(intToCheck, Nothing) Then
If you have .Net 3.5 ability you can create an extension method for strings.
Public Module MyExtensions
<System.Runtime.CompilerServices.Extension()> _
Public Function IsInteger(ByVal value As String) As Boolean
If String.IsNullOrEmpty(value) Then
Return False
Else
Return Integer.TryParse(value, Nothing)
End If
End Function
End Module
And then call like:
If value.IsInteger() Then
Sorry, getting carried away I know, but also you can add this to the MyExtensions class above in .Net 3.5 and not worry unless you need validations.
<System.Runtime.CompilerServices.Extension()> _
Public Function ToInteger(ByVal value As String) As Integer
If value.IsInteger() Then
Return Integer.Parse(value)
Else
Return 0
End If
End Function
Then simply use
value.ToInteger()
This will return 0 if it isn't a valid Integer.
Since you are using VB.net you can use the IsNumeric Function
If IsNumeric(myInt) Then
'Do Suff here
End If
public static class Util {
public static Int32? ParseInt32(this string text) {
Int32 result;
if(!Int32.TryParse(text, out result))
return null;
return result;
}
public static bool IsParseInt32(this string text) {
return text.ParseInt32() != null;
}
}
Try this code.
Module IntegerHelpers
Function IsInteger(ByVal p1 as String) as Boolean
Dim unused as Integer = 0
return Integer.TryParse(p1,unused)
End Function
End Module
The nice part is that since it's declared as a Module level function it can be used without a qualifier. Example Usage
return IsInteger(mInt)
Why not write an extension method to clean up your code? I haven't written VB.Net for a while, but here is an example in c#:
public static class MyIntExtensionClass
{
public static bool IsInteger(this string value)
{
if(string.IsNullOrEmpty(value))
return false;
int dummy;
return int.TryParse(value, dummy);
}
}
J Ambrose Little performed timing tests for IsNumeric checks back in 2003. You may wish to retry the mentioned tests with v2 of the CLR.
A variation would be:
Int32.TryParse(input_string, Globalization.NumberStyles.Integer)

How can I access a class variable via an array in VB.NET?

If I have the following class and declaration:
Public Class objLocation
Public SysLocationId As String
Public NameFull As String
Public LatRaw As String
Public LongRaw As String
Public Active As Integer
End Class
dim lLocation as new objLocation
I can access each variable thus lLocation.SysLocationId, etc. Is there an alternate way, so I can access each variable by index, so something like lLocation(0), lLocation(1), etc., which gives me the flexibility to compare to classes of the same type via a for next loop, or against other sources, like a datatable.
If your goal is comparison, usually what you'll do is implement the IComparable interface or overload the >, < operators (if an ordering is needed) or just the = operator (if equivalence is needed).
You just write one function in one location and invoke that function whenever you need to do your comparison. The same goes for comparing to objects stored in a database. Where you put these functions depends on your application architecture, but for the object-object comparison you can have it as part of the objLocation class itself.
There is no built-in langauge support for this. However you can simulate this by creating a default indexer property on the class
Public Class objLocation
...
Default Public ReadOnly Property Indexer(ByVal index As Integer)
Get
Select Case index
Case 0
Return SysLocationId
Case 1
Return NameFull
Case 2
Return LatRaw
Case 3
Return LongRaw
Case 4
Return Active
Case Else
Throw New ArgumentException
End Select
End Get
End Property
Then you can use it as follows
Dim x As objLocation = GetObjLocation
Dim latRaw = x(2)
No, you can not do this outright.
You have to use reflection to get the properties, but you have to be aware that there is no guarantee on the order of the properties returned (which is important if you want to index them numerically).
Because of that, you will have to keep the sort order consistent when working with the properties (and indexes).
Are you looking for a List:
Dim LocationList As List<objLocation>;
For Each loc As objLocation In LocationList
loc.whatever
Next
or to use the index:
For i = 0 To LocationList.Length - 1
LocationList(i).whatever
Next
sorry, if the VB syntax isn't right...I've been doing C# lately and no VB
You can do that as follows. It is C# and something is a bit different with using indexers in VB, but you should absolutly be able to get it working in VB.
public class ObjLocation
{
private String[] Properties = new String[5];
public const Int32 IndexSysLocationId = 0;
public const Int32 IndexNameFull = 1;
public const Int32 IndexLatRaw = 2;
public const Int32 IndexLongRaw = 3;
public const Int32 IndexActive = 4;
// Repeat this for all properties
public String SysLocationId
{
get { return this.Properties[ObjLocation.IndexSysLocationId]; }
set { this.Properties[ObjLocation.IndexSysLocationId] = value; }
}
public String this[Int32 index]
{
get { return this.Properties[index]; }
set { this.Properties[index] = value; }
}
}
Now you have the object with the properties as before, but stored in an array and you can also access them through an indexer.
This method I implemented in a public structure to return an array of string variables stored in a structure:
Public Shared Function returnArrayValues() As ArrayList
Dim arrayOutput As New ArrayList()
Dim objInstance As New LibertyPIMVaultDefaultCategories()
Dim t As Type = objInstance.GetType()
Dim arrayfinfo() As System.Reflection.FieldInfo = t.GetFields()
For Each finfo As System.Reflection.FieldInfo In arrayfinfo
Dim str As String = finfo.GetValue(objInstance)
arrayOutput.Add(str)
Next
Return arrayOutput
End Function
Put it inside the structure or a class. Maybe this sample code helps.

Unexpected Interface Conversion

I just discovered, quite by accident, that this seems to work:
Public Interface Ix
ReadOnly Property TestProp()
End Interface
Public Interface Iy
Property TestProp()
End Interface
Public Sub TestSub
Dim x As Ix = Me.InstantiationNotImportant()
Dim y As Iy = CType(x, Iy)
End Sub
Maybe I've written a bit too much code today, but this doesn't make sense to me. How is it possible that I can convert one interface to another one that is even slightly different?
Any thoughts?
EDIT: It appears that I was indeed just light-headed from too much coding. After a little sleep, the world makes sense again. :)
Like Garry said Instantiation is important because if I do this:
public interface IX { }
public interface IY { }
public class Test : IX { }
The following won't work.
IX xvar = new Test();
IY yvar = xvar as IY; \\Returns null.
IY yvar = (IY)xvar; \\Throws cast exception.
it runs but yvar will be null because the cast is not possible, but if you declare test like this:
public class Test : IX,IY { }
It will now work, as Test uses both interfaces and casting from the object in xvar to Y is valid.
Instantiation is important as that method could produce an object that implements both interfaces making this code make complete sense. Otherwise, I'm not sure.