Determine the length of a generic type? - vb.net

How can I at run-time determine the length of a generic type (with constraint Structure).
I need the byte count to create a view accessor of a MemoryMappedFile (which is initialized in the constructor).
Private goVirtualFile As MemoryMappedFile
Private glLength As Long = 0
Public Class CTest(Of T As Structure)
Public Sub Append(tData As T())
Dim iNumStruct As Integer = tData.Length 'Number of structures.
Dim iStructLen As Integer = ... 'Length of 1 structure in bytes.
Dim iBytes As Integer = iNumStruct * iStructLen 'Total length in bytes.
Using goViewStream = goVirtualFile.CreateViewAccessor(
glLength, iBytes)
...
End Using
End Sub
Public Function Read(lOffset As Long, iNumStruct As Integer) As T()
...
End Sub
End Class

Related

What is the fastest way to retrieve at runtime big powers of two in decimal string format?

In order to display big numbers I need to be able to retrieve the powers of two in decimal string format. The following code is the best I could do, is there a faster way?
Public NotInheritable Class TwoPowerOf
Private DecimalString As String = ""
Public Sub New(ByVal MyInteger As Integer)
If MyInteger > -256 And MyInteger < 1024 Then
Me.DecimalString = GetTwoPowerOf(MyInteger)
End If
End Sub
Public Overrides Function ToString() As String
Return Me.DecimalString
End Function
Protected Function GetTwoPowerOf(ByVal MyInteger As Integer) As String
Dim result As String = ""
Dim d As New Dictionary(Of Integer, String)
'...
d.Add(2, "4")
d.Add(1, "2")
d.Add(0, "1")
d.Add(-1, "0.5")
d.Add(-2, "0.25")
d.Add(-3, "0.125")
d.Add(-4, "0.0625")
d.Add(-5, "0.03125")
d.Add(-6, "0.015625")
d.Add(-7, "0.0078125")
d.Add(-8, "0.00390625")
' ...
result = d.Item(MyInteger)
Return result
End Function
End Class
And retreiving is something like this:
Sub whatever()
Dim MyInteger as Integer
Dim MyDecimalString as String = New TwoPowerOf(MyInteger).ToString
Console.WriteLine(MyDecimalString)
End Sub
Or, is there a way to convert big binary numbers into decimals without using the powers of two?

Merge two Array Properties in Class

I have a Class (TestClass) with the following three properties:
Private myArr1() As String
Private myArr2() As String
Private myFinalArray() As String
Private Sub Class_Initialize()
ReDim myArr1(0 To 3)
ReDim myArr2(0 To 2)
ReDim myFinalArray(0 To 6)
End Sub
Public Property Get arr1(ByVal index As Long) As Double
arr1 = myArr1(index)
End Property
Public Property Let arr1(ByVal index As Long, ByVal myvalue As Double)
myArr1(index) = myvalue
End Property
Public Property Get arr2(ByVal index As Long) As Double
...
Public Property Let arr2(ByVal index As Long, ByVal myvalue As Double)
...
Public Property Get FinalArray(ByVal index As Long) As Double
...
Public Property Let FinalArray(ByVal index As Long, ByVal myvalue As Double)
...
Here we have just two arrays that I fill with data:
Sub test()
Dim t As TestClass
Set t = New TestClass
For i = 0 To 3
t.arr1(i) = i
Next
For i = 0 To 2
t.arr2(i) = i
Next
t.GetFinalValues (t)
End Sub
My Problem now is that these array elements must be rearranged according to a confused pattern I want to write a property for that but it is not working. My idea was to add the following function to my class:
Public Function GetFinalValues(ByRef t As TestClass) As Double()
'Imput parameter arrX can ben the Value as well as the Bench arrays.
Dim arr1(2) As Double
Dim arr2(3) As Double
Dim i As Integer
Dim arrCollection(6) As Double
arrCollection(0) = t.arr1(0)
arrCollection(1) = t.arr2(0)
arrCollection(2) = t.arr2(1)
arrCollection(3) = t.arr1(1)
arrCollection(4) = t.arr2(2)
arrCollection(6) = t.arr1(2)
arrCollection(5) = t.arr2(3)
'Assign return object
For i = 0 To 6
FinalArray(i) = arrCollection(i)
Next i
GetFinalValues
End Function
If I run this the code stops at t.GetFinalValues(t) giving me the Errormessage: Object doesent support property or method. Anyone who can help me get this working? Or has a rebuild idea for a even better solution to that problem?
EDIT: I added vb.net since this might be a construction problem that is not specified to vba
You have two issues:
First you should remove the parentheses from this line:
t.GetFinalValues (t)
so it's just:
t.GetFinalValues t
Then your function needs to return a String array not Double, since that's the type of the private variable. Your class code becomes something like this:
Private Sub Class_Initialize()
ReDim myArr1(0 To 3)
ReDim myArr2(0 To 2)
ReDim myFinalArray(0 To 6)
End Sub
Public Property Get arr1(ByVal index As Long) As Double
arr1 = myArr1(index)
End Property
Public Property Let arr1(ByVal index As Long, ByVal myvalue As Double)
myArr1(index) = myvalue
End Property
Public Property Get arr2(ByVal index As Long) As Double
arr2 = myArr1(index)
End Property
Public Property Let arr2(ByVal index As Long, ByVal myvalue As Double)
myArr2(index) = myvalue
End Property
Public Property Get FinalArray(ByVal index As Long) As Double
FinalArray = myArr1(index)
End Property
Public Property Let FinalArray(ByVal index As Long, ByVal myvalue As Double)
myFinalArray(index) = myvalue
End Property
Public Function GetFinalValues(ByRef t As TestClass) As String()
'Imput parameter arrX can ben the Value as well as the Bench arrays.
Dim arr1(2) As Double
Dim arr2(3) As Double
Dim i As Integer
Dim arrCollection(6) As Double
arrCollection(0) = t.arr1(0)
arrCollection(1) = t.arr2(0)
arrCollection(2) = t.arr2(1)
arrCollection(3) = t.arr1(1)
arrCollection(4) = t.arr2(2)
arrCollection(6) = t.arr1(2)
arrCollection(5) = t.arr1(3)
'Assign return object
For i = 0 To 6
FinalArray(i) = arrCollection(i)
Next i
GetFinalValues = myFinalArray
End Function
Note that you were also trying to use t.arr2(3) which exceeds the number of elements in arr2 so I assumed you meant t.arr1(3)

Enum with string index or alternative

Is it possible to return a value from enum with a string index? For example I can use:
Enum test
firstval
secondval
thirdval
End Enum
Dim index As Integer = 1
CType(index, test).ToString()
to return firstval but is there a way to do something similar where index is a string value? For example:
Enum test
firstval = "one"
secondval = "two"
thirdval = "three"
End Enum
Dim index As string = "one"
CType(index, test).ToString()
It's not possible using an Enum, but you could easily create a type that can do what you want, using the Narrowing operator.
simple example:
Class Test
Private Shared _lookup As Dictionary(Of String, Test)
Private Key As String
Private Name As String
Public Shared ReadOnly firstval As Test = New Test("one", "firstval")
Public Shared ReadOnly secondval As Test = New Test("two", "secondval")
Public Shared ReadOnly thirdval As Test = New Test("three", "thirdval")
Private Sub New(key As String, name As String)
Me.Key = key
Me.Name = name
If _lookup Is Nothing Then _
_lookup = New Dictionary(Of String, Test)
_lookup.Add(key, Me)
End Sub
Public Overrides Function ToString() As String
Return Me.Name ' or whatever you want '
End Function
Public Shared Widening Operator CType(obj As Test) As String
Return obj.Key
End Operator
Public Shared Narrowing Operator CType(key As String) As Test
Return _lookup(key)
End Operator
End Class
usage:
Dim index As string = "one"
' returns firstval '
CType(index, Test).ToString()
There are several other alternatives.
One is to get the names used in the enum. For instance:
Friend Enum ImgFormat
Bitmap
GIF
JPeg
TIFF
PNG
End Enum
Dim ImgNames() As String
...
ImgNames = [Enum].GetNames(GetType(ImgFormat))
If your names are not friendly enough, decorate them with Descriptions:
Imports System.ComponentModel
Friend Enum ImgFormat
<Description("Bitmap (BMP)")> Bitmap
<Description("Graphic Interchange (GIF)")> GIF
<Description("Jpg/JPeg (JPG)")> JPeg
<Description("Tagged Image (TIFF)")> TIFF
<Description("Portable Graphics (PNG)")> PNG
End Enum
To get the descriptions, requires reflection which gets involved:
Imports System.Reflection
Imports System.ComponentModel
Public Class EnumConverter
' gets a single enum description
Public Shared Function GetEnumDescription(ByVal EnumConstant As [Enum]) As String
Dim fi As FieldInfo = EnumConstant.GetType().GetField(EnumConstant.ToString())
Dim attr() As DescriptionAttribute = _
DirectCast( _
fi.GetCustomAttributes(GetType(DescriptionAttribute), False), _
DescriptionAttribute() )
If attr.Length > 0 Then
Return attr(0).Description
Else
Return EnumConstant.ToString()
End If
End Function
' get all the enum descriptions:
Public Shared Function GetEnumDescriptions(ByVal type As Type) As String()
Dim n As Integer = 0
Dim enumValues As Array = [Enum].GetValues(type)
Dim Descr(enumValues.Length - 1) As String
For Each value As [Enum] In enumValues
Descr(n) = GetEnumDescription(value)
n += 1
Next
Return Descr
End Function
End Class
To use:
Dim ImgNames() As String = EnumConverter.GetEnumDescriptions(ImgFormat)
ImgNames(ImgFormat.GIF) would be 'Graphic Interchange (GIF)'
This will break if the Enum values are not the default 0, 1, 2 ... IF that is an issue (and it really is), then build a class around it to store the Name or Description with the Enum Value. Rather than building a class to create a pseudo enum, make one to create a list of name-value pairs consisting of the Descriptions and Enum Value.

VB Assignment of member field programmatically

This question is a follow-on to VB ReDim of member field programmatically. After the arrays are dimensioned appropriately, I try to set the values of the elements, but I get an exception at run time when I try to assign the first value (MySB.AssignValues(0, "B", 0, 7.6))
System.InvalidCastException was unhandled
HResult=-2147467262
Message=Object cannot be stored in an array of this type.
Source=mscorlib
Module TestSetArray
Public Class BS
Public A As String
Public B() As Double
Public C() As Double
End Class
Public Class SB
Public MyBS() As BS
'ReadFieldString is a function that returns a string of the field name of Class BS,
'i.e., A, B or C. For test purpose, retun a constant
Public Function ReadFieldString() As String
Return "B"
End Function
'GetArrayDim is a function that returns an integer, which is the size of the array
'of that field name. For test purpose, retun a constant
Public Function GetArrayDim() As Integer
Return 2
End Function
Public Sub DimArrays()
ReDim MyBS(3)
Dim i As Integer
For i = 0 To MyBS.Length - 1
MyBS(i) = New BS()
Dim f = GetType(BS).GetField(ReadFieldString())
f.SetValue(MyBS(i), Array.CreateInstance(f.FieldType.GetElementType(), GetArrayDim()))
Next
End Sub
Public Sub AssignValues(MainIndex As Integer, TheName As String, TheIndex As Integer, TheValue As Double)
Dim f = MyBS(MainIndex).GetType.GetMember(TheName)
f.SetValue(TheValue, TheIndex)
End Sub
End Class
Sub Main()
Dim MySB As SB = New SB
MySB.DimArrays()
MySB.AssignValues(0, "B", 0, 7.6)
MySB.AssignValues(0, "B", 1, 8.2)
End Sub
End Module
Thanks in advance.
The problem is that the GetMember method returns an array of type MemberInfo, not the double array of the class. You'd probably have an easier time if you used GetField instead. You have to call GetValue and cast its result to an Array in order to use SetValue to set the value.
Public Sub AssignValues(MainIndex As Integer, TheName As String, TheIndex As Integer, TheValue As Double)
Dim f = MyBS(MainIndex).GetType().GetField(TheName)
Dim doubleArray = DirectCast(f.GetValue(MyBS(MainIndex)), Array)
doubleArray.SetValue(TheValue, TheIndex)
End Sub
or if you know that the array will always be an array of Double, you can cast it directly to that:
Public Sub AssignValues(MainIndex As Integer, TheName As String, TheIndex As Integer, TheValue As Double)
Dim f = MyBS(MainIndex).GetType().GetField(TheName)
Dim doubleArray = DirectCast(f.GetValue(MyBS(MainIndex)), Double())
doubleArray(TheIndex) = TheValue
End Sub

VB ReDim of member field programmatically

I am trying to ReDim a member array based on reading a file. I cannot figure out how to do it. This is what I tried, but it does not work.
Public Class BS
Public A() As String
Public B() As Double
Public C() As Double
End Class
Public Class SB
Public MyBS() As BS
'ReadFieldString is a function that returns a string of the field name of Class BS,
'i.e., A, B or C. For test purpose, retun a constant
Public Function ReadFieldString() As String
Return "B"
End Function
'GetArrayDim is a function that returns an integer, which is the size of the array
'of that field name. For test purpose, retun a constant
Public Function GetArrayDim() As Integer
Return 1
End Function
Public Sub DimArrays()
ReDim MyBS(3)
Dim i As Integer
For i = 0 To MyBS.Length - 1
'Try to ReDim the member of MyBS
ReDim MyBS(i).GetType.GetField(ReadFieldString)(GetArrayDim)
Next()
End Sub
End Class
The ReDim statement has the error "Expression is a value and therefore cannot be the target of an assignment."
Thanks in advance.
I'm not sure ReDim works like that. Changing the code to this will achieve what I believe you are after:
Public Sub DimArrays()
ReDim MyBS(3)
Dim i As Integer
For i = 0 To MyBS.Length - 1
MyBS(i) = New BS()
Dim f = GetType(BS).GetField(ReadFieldString())
f.SetValue(MyBS(i), Array.CreateInstance(f.FieldType.GetElementType(), GetArrayDim()))
Next
End Sub
However, I think a better approach would be to specify the array size in the BS constructor.