Stepped table lookup in VB? - vb.net

I use this code from the book that illustartes exampel of stepped table looup:
Imports System
Imports Microsoft.VisuaLBasic
Public Module Module1
Public Sub Main()
Dim rangeLimit() as Double = {50.0, 65.0, 75.0, 90.0, 100.0}
Dim grade() as String = {"F", "D", "C", "B", "A"}
Dim maxGradeLevel = grade.length - 1
Dim gradeLevel = 0
Dim studentGrade = "A"
Dim studentScore = 50
While((studentGrade = "A") and (gradeLevel < maxGradeLevel))
if(studentScore < rangeLimit(gradeLevel)) then
studentGrade = grade(gradeLevel)
End if
gradeLevel = gradeLevel + 100
End While
Print(studentGrade)
End Sub
End Module
Code is here
I wonder how does it work and how to fix this error after compiling:
Run-time exception (line -1): Conversion from string "A" to type 'Integer' is not valid.

You probably want Console.WriteLine() instead of Print().
Also:
Imports System
Imports System.Linq
Public Module Module1
Public Sub Main()
Dim studentScore As Double = 50.0
Console.WriteLine(GetGrade(studentScore))
End Sub
Public Function GetGrade(score As Double) As String
Dim gradeTable = {
(50.0, "F"),
(65.0, "D"),
(75.0, "C"),
(90.0, "B"),
(100.0, "A")
}
Return gradeTable.First(Function(g) g.Item1 >= Score).Item2
End Function
End Module
See it work here:
https://dotnetfiddle.net/CKTNCE
Personally, though, I prefer to use the minimum grade instead of the maximum for the boundaries. I find it far more likely you'll have extra credit push a score above 100 than you'll have something send you a negative score, and using maximum grades causes problems in that situation:
Imports System
Imports System.Linq
Public Module Module1
Public Sub Main()
Dim studentScore As Double = 50.0
Console.WriteLine(GetGrade(studentScore))
End Sub
Public Function GetGrade(score As Double) As String
Dim gradeTable = {
(90.0, "A"),
(75.0, "B"),
(65.0, "C"),
(50.0, "D"),
( 0.0, "F")
}
Return gradeTable.First(Function(g) g.Item1 >= Score).Item2
End Function
End Module
You also need to be careful with your equality comparisons. >= and > mean different things, and only one is correct.

Related

"var" variable is used before it is assigned a value

It seems like I need to assign some values into variable var() and I don't know how. Can someone help me fix this please.
Imports System
Imports System.IO
Module Module1
Sub Main()
Dim i As Integer
Dim var() As String
Dim lines() As String = IO.File.ReadAllLines("C:\Users\carment\Desktop\Test.txt")
i = 1
For Each line As String In lines
var(i) = line
Console.WriteLine(var(i))
i = i + 1
Next
End Sub
End Module
You have to initialize the array as well:
var = New String(lines.Length-1) {}

Retrieving information out of a Class module collection in VB.Net

Currently I'm having an issue/Struggling to understand how to pull the information out of a Class Module.
How I understand it is if a Class Module was an Excel sheet an instance would be a row and the public property would be the columns I have issued this problem before see link (Retrieving information from a Class module VB.Net) here is where i am with the code
In side my Class Module
Public Class tDCVillains
Public Property Gothem As Integer
Public Property metropolis as Integer
End Class
Inserting the Information into the Class Module
Sub GrabAccessInfo()
Dim DCVillains As New tDCVillains
Dim VillainsCollection As New Collection
DCVillains.Gothem = rst("Gothem").Value
DCVillains.metropolis = rst("metropolis").Value
VillainsCollection.Add(DCVillains)
rst.MoveNext()
End Sub
Retrieving information out of the Class Module
Sub RackSlotAccess(DCVillains As tDCVillains)
For Each tDCVillains As System.Reflection.PropertyInfo In tDCVillains ' its not liking tDCVillains
Dim ObjGothem = DCVillains.Gothem
Dim Objmetropolis = DCVillains.metropolis
If ObjGothem >= 1 Then
InsertGothemVillains(ObjGothem, 32, "I", Slot, Rack)
End If
If Objmetropolis >= 1 Then
InsertmetropolisVillains(Objmetropolis, 16, "I", Slot, Rack)
End If
Next
End Sub
its the for each statement the code doesn't like but i cant figure out why?
It seems as if you want to loop the properties of the type tDCVillains. You can use Type.GetProperties:
Sub RackSlotAccess(DCVillains As tDCVillains)
Dim type = GetType(tDCVillains)
For Each tDCVillains As System.Reflection.PropertyInfo In type.GetProperties()
Dim ObjGothem = DCVillains.Gothem
Dim Objmetropolis = DCVillains.metropolis
If ObjGothem >= 1 Then
InsertGothemVillains(ObjGothem, 32, "I", Slot, Rack)
End If
If Objmetropolis >= 1 Then
InsertmetropolisVillains(Objmetropolis, 16, "I", Slot, Rack)
End If
Next
End Sub

Different Results using Parallel foreach everytime Excel Worksheet is read

Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Collections.Concurrent
Imports Excel = Microsoft.Office.Interop.Excel
Public Class TestCarDatas
Public Property RowID As Integer
Public Property ModelYear As Integer
Public Property VehMfcName As String
Public Property EmgVeh As Boolean
End Class
Module ExcelParallelDataGather2
Public Const ExcelVehDataPath As String = "D:\Users\Dell\Desktop"
Public rwl As New System.Threading.ReaderWriterLock()
Public rwl_writes As Integer = 0
Public FullTestVehData As New List(Of TestCarDatas)()
Public x1App As New Excel.Application
Public x1Workbook As Excel.Workbook
Public x1Worksheet1 As Excel.Worksheet
Public x1WkshtLrow As Integer
Sub main()
x1App.Visible = False
ErrorNotify = False
Console.WriteLine("Excel Parallel foreach operation program....")
Dim cki As ConsoleKeyInfo
x1Workbook = x1App.Workbooks.Open(Path.Combine(ExcelVehDataPath, "TestCarDatabase2014.xls"), , True)
x1Worksheet1 = x1Workbook.Sheets(1)
Do
Console.WriteLine("Press escape key to exit, 'a' key to reiterate, 'c' key to clear console")
cki = Console.ReadKey()
If Chr(cki.Key).ToString = "A" Then
Console.WriteLine("--> Processing...")
FullTestVehData.Clear()
rwl_writes = 0
Parallel.ForEach(Partitioner.Create(11, x1WkshtLrow + 1), _
Function()
' Initialize the local states
Return New List(Of TestCarDatas)()
End Function, _
Function(partrange, loopState, localState)
' Accumulate the thread-local computations in the loop body
localState = populateCardata(x1Worksheet1, partrange.Item1, partrange.Item2)
Return (localState)
End Function, _
Sub(finalstate)
' Combine all local states
Try
rwl.AcquireWriterLock(Timeout.Infinite)
Try
' It is safe for this thread to read or write
' from the shared resource in this block
FullTestVehData.AddRange(finalstate)
Interlocked.Increment(rwl_writes)
Finally
' Ensure that the lock is released.
rwl.ReleaseWriterLock()
End Try
Catch ex As ApplicationException
' The writer lock request timed out.
End Try
End Sub)
End If
If Chr(cki.Key).ToString = "C" Then
Console.Clear()
Console.WriteLine("Excel Parallel foreach operation program....")
End If
If Chr(cki.Key).ToString <> "A" And Chr(cki.Key).ToString <> "C" And _
cki.Key <> ConsoleKey.Escape Then
Console.WriteLine("")
Console.WriteLine("Invalid response via key press")
End If
Loop While (cki.Key <> ConsoleKey.Escape)
End Sub
Friend Function populateCardata(ByVal WksheetObj As Excel.Worksheet, ByVal rngStart As Integer, _
ByVal rngStop As Integer) As List(Of TestCarDatas)
Dim wkrng(12) As String
Dim PartVehData As New List(Of TestCarDatas)
PartVehData.Clear()
For i As Integer = rngStart To rngStop - 1
Dim data As New TestCarDatas
For j As Integer = 0 To 12
wkrng(j) = WksheetObj.Cells(i, j + 1).Address(RowAbsolute:=False, ColumnAbsolute:=False)
Next
With data
.RowID = i
.ModelYear = WksheetObj.Range(wkrng(0)).Value2
.VehMfcName = WksheetObj.Range(wkrng(1)).Value2
If WksheetObj.Range(wkrng(11)).Value2 = "Y" Then
.EmgVeh = True
Else
.EmgVeh = False
End If
End With
PartVehData.Add(data)
Next
Return PartVehData
End Function
End Module
I am trying to get the Excel Worksheet data using parallel foreach and range Partitioner, creating lists in thread local storage and finally adding them using thread safe methods like synclock or reader-writer locks
Rows from 11 to last row in worksheet are to be read and populated in a List(of T)
I observe following when I execute above code
When rows in worksheet are greater(example >2000), this code works as expected everytime
When rows in worksheet are less, this code returns partial list during first few iteration (data from some of the partitioner ranges are lost). If I re-iterate it (pressing key 'a') multiple times, then sometimes it returns expected results (final list count = no. of excel rows required to be read)
Why this phenomenon is observed?
What is the solution using parallel foreach, if I need correct results during first run/iteration irrespective of no. of rows in worksheet?

Get VB.net Enum Description from Value

How can I get Enum description from its value?
I can get the description from the name using:
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
But I cant figure out how to pass a variable name to this function. I've tried things like
GetEnumDescription([Enum].GetName(GetType(myEnum), 2)))
but nothing I've tried is correct.
If you have a variable of your enum type, it's simply
GetEnumDescription(myEnum)
Minimal working example:
Enum TestEnum
<Description("Description of Value1")>
Value1
End Enum
Public Sub Main()
Dim myEnum As TestEnum = TestEnum.Value1
Console.WriteLine(GetEnumDescription(myEnum)) ' prints "Description of Value1"
Console.ReadLine()
End Sub
If you have an Integer variable, you need to cast it to your enum type first (CType works as well):
GetEnumDescription(DirectCast(myEnumValue, TestEnum))
Working example:
Enum TestEnum
<Description("Description of Value1")>
Value1 = 1
End Enum
Public Sub Main()
Console.WriteLine(GetEnumDescription(DirectCast(1, TestEnum)))
Console.ReadLine()
End Sub
The source for your confusion seems to be a misunderstanding: Your method does not take the "name" of an enum as a parameter, it takes an Enum as a parameter. That's something different, and it's also the reason why your attempts to use GetName failed.
Here's another solution to get an Enum's description as an extension.
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
<Extension()> Public Function GetEnumDescription(ByVal EnumConstant As [Enum]) As String
Dim attr() As DescriptionAttribute = DirectCast(EnumConstant.GetType().GetField(EnumConstant.ToString()).GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())
Return If(attr.Length > 0, attr(0).Description, EnumConstant.ToString)
End Function
Example use from the previous posts:
Enum Example
<Description("Value1 description.")> Value1 = 1
<Description("Value2 description.")> Value2 = 2
End Enum
Sub Main()
Console.WriteLine(DirectCast(2, Example).GetEnumDescription())
Console.ReadLine()
End Sub

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