Write a .txt with values of three listboxes - vb.net

I have to export a .txt file with the values of three listboxes per each row. I've tried to to this with the following code:
Using writer = New StreamWriter(SaveFileDialog1.FileName)
For Each o As String In Form10.ListBox1.Items.Cast(Of Object).Zip(Form10.ListBox2.Items.Cast(Of Object).Zip(Form6.ListBox2.Items.Cast(Of Object)), Function(x1, x2, x3) CStr(x1) & "," & CStr(x2) & "," & CStr(x3))
writer.WriteLine(o)
Next
End Using
I'm receiving several errors:
Error BC36646 Data type(s) of the type parameter(s) in extension method 'Public Function Zip(Of TSecond, TResult)(second As IEnumerable(Of TSecond), resultSelector As Func(Of Object, TSecond, TResult)) As IEnumerable(Of TResult)' defined in 'Enumerable' cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
Error BC36586 Argument not specified for parameter 'resultSelector' of extension method 'Public Function Zip(Of TSecond, TResult)(second As IEnumerable(Of TSecond), resultSelector As Func(Of Object, TSecond, TResult)) As IEnumerable(Of TResult)' defined in 'Enumerable'.
Error BC42020 Variable declaration without an 'As' clause; type of Object assumed.
Unfortunately, while Form10.Listbox1 and Form10.Listbox2 are meant to be of the same size, Form6.Listbox6 is smaller; so the file I need to be exported should be with the following format:
F10.LB1,F10.LB2,F6.LB2 - for the lenght of Form6.Listbox6 and the F10.LB1,F10.LB2 for the rest of the items. If you need more explanations, please comment or answer. Thanks all are going to write me here. Best regards.

Edit :
Using writer = New StreamWriter("d:\test.txt")
For id As Integer = 0 To ListBox1.Items.Count - 1
Dim to_write As String = ListBox1.Items(id) + "," + ListBox2.Items(id)
If (ListBox3.Items.Count -1 >= id ) Then
to_write += "," + ListBox3.Items(id)
End If
writer.WriteLine(to_write)
Next
End Using
Dont forget Count -1 ;if you have 5 items : 0 to 4 = 5 items.
Are you ok with this way :
Using writer = New StreamWriter("d:\test.txt")
For Each o As String In ListBox1.Items
writer.WriteLine(o)
Next
For Each o As String In ListBox2.Items
writer.WriteLine(o)
Next
For Each o As String In ListBox3.Items
writer.WriteLine(o)
Next
End Using
Or for all listboxes :
Using writer = New StreamWriter("d:\test.txt")
For Each lbx As ListBox In Me.Controls.OfType(Of ListBox)
For Each o As String In lbx.Items
writer.WriteLine(o)
Next
Next
End Using

Related

Get a specific value from the line in brackets (Visual Studio 2019)

I would like to ask for your help regarding my problem. I want to create a module for my program where it would read .txt file, find a specific value and insert it to the text box.
As an example I have a text file called system.txt which contains single line text. The text is something like this:
[Name=John][Last Name=xxx_xxx][Address=xxxx][Age=22][Phone Number=8454845]
What i want to do is to get only the last name value "xxx_xxx" which every time can be different and insert it to my form's text box
Im totally new in programming, was looking for the other examples but couldnt find anything what would fit exactly to my situation.
Here is what i could write so far but i dont have any idea if there is any logic in my code:
Dim field As New List(Of String)
Private Sub readcrnFile()
For Each line In File.ReadAllLines(C:\test\test_1\db\update\network\system.txt)
For i = 1 To 3
If line.Contains("Last Name=" & i) Then
field.Add(line.Substring(line.IndexOf("=") + 2))
End If
Next
Next
End Sub
Im
You can get this down to a function with a single line of code:
Private Function readcrnFile(fileName As String) As IEnumerable(Of String)
Return File.ReadLines(fileName).Where(Function(line) RegEx.IsMatch(line, "[[[]Last Name=(?<LastName>[^]]+)]").Select(Function(line) RegEx.Match(line, exp).Groups("LastName").Value)
End Function
But for readability/maintainability and to avoid repeating the expression evaluation on each line I'd spread it out a bit:
Private Function readcrnFile(fileName As String) As IEnumerable(Of String)
Dim exp As New RegEx("[[[]Last Name=(?<LastName>[^]]+)]")
Return File.ReadLines(fileName).
Select(Function(line) exp.Match(line)).
Where(Function(m) m.Success).
Select(Function(m) m.Groups("LastName").Value)
End Function
See a simple example of the expression here:
https://dotnetfiddle.net/gJf3su
Dim strval As String = " [Name=John][Last Name=xxx_xxx][Address=xxxx][Age=22][Phone Number=8454845]"
Dim strline() As String = strval.Split(New String() {"[", "]"}, StringSplitOptions.RemoveEmptyEntries) _
.Where(Function(s) Not String.IsNullOrWhiteSpace(s)) _
.ToArray()
Dim lastnameArray() = strline(1).Split("=")
Dim lastname = lastnameArray(1).ToString()
Using your sample data...
I read the file and trim off the first and last bracket symbol. The small c following the the 2 strings tell the compiler that this is a Char. The braces enclosed an array of Char which is what the Trim method expects.
Next we split the file text into an array of strings with the .Split method. We need to use the overload that accepts a String. Although the docs show Split(String, StringSplitOptions), I could only get it to work with a string array with a single element. Split(String(), StringSplitOptions)
Then I looped through the string array called splits, checking for and element that starts with "Last Name=". As soon as we find it we return a substring that starts at position 10 (starts at zero).
If no match is found, an empty string is returned.
Private Function readcrnFile() As String
Dim LineInput = File.ReadAllText("system.txt").Trim({"["c, "]"c})
Dim splits = LineInput.Split({"]["}, StringSplitOptions.None)
For Each s In splits
If s.StartsWith("Last Name=") Then
Return s.Substring(10)
End If
Next
Return ""
End Function
Usage...
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TextBox1.Text = readcrnFile()
End Sub
You can easily split that line in an array of strings using as separators the [ and ] brackets and removing any empty string from the result.
Dim input As String = "[Name=John][Last Name=xxx_xxx][Address=xxxx][Age=22][Phone Number=8454845]"
Dim parts = input.Split(New Char() {"["c, "]"c}, StringSplitOptions.RemoveEmptyEntries)
At this point you have an array of strings and you can loop over it to find the entry that starts with the last name key, when you find it you can split at the = character and get the second element of the array
For Each p As String In parts
If p.StartsWith("Last Name") Then
Dim data = p.Split("="c)
field.Add(data(1))
Exit For
End If
Next
Of course, if you are sure that the second entry in each line is the Last Name entry then you can remove the loop and go directly for the entry
Dim data = parts(1).Split("="c)
A more sophisticated way to remove the for each loop with a single line is using some of the IEnumerable extensions available in the Linq namespace.
So, for example, the loop above could be replaced with
field.Add((parts.FirstOrDefault(Function(x) x.StartsWith("Last Name"))).Split("="c)(1))
As you can see, it is a lot more obscure and probably not a good way to do it anyway because there is no check on the eventuality that if the Last Name key is missing in the input string
You should first know the difference between ReadAllLines() and ReadLines().
Then, here's an example using only two simple string manipulation functions, String.IndexOf() and String.Substring():
Sub Main(args As String())
Dim entryMarker As String = "[Last Name="
Dim closingMarker As String = "]"
Dim FileName As String = "C:\test\test_1\db\update\network\system.txt"
Dim value As String = readcrnFile(entryMarker, closingMarker, FileName)
If Not IsNothing(value) Then
Console.WriteLine("value = " & value)
Else
Console.WriteLine("Entry not found")
End If
Console.Write("Press Enter to Quit...")
Console.ReadKey()
End Sub
Private Function readcrnFile(ByVal entry As String, ByVal closingMarker As String, ByVal fileName As String) As String
Dim entryIndex As Integer
Dim closingIndex As Integer
For Each line In File.ReadLines(fileName)
entryIndex = line.IndexOf(entry) ' see if the marker is in our line
If entryIndex <> -1 Then
closingIndex = line.IndexOf(closingMarker, entryIndex + entry.Length) ' find first "]" AFTER our entry marker
If closingIndex <> -1 Then
' calculate the starting position and length of the value after the entry marker
Dim startAt As Integer = entryIndex + entry.Length
Dim length As Integer = closingIndex - startAt
Return line.Substring(startAt, length)
End If
End If
Next
Return Nothing
End Function

Function CallByName with args out of order

I'm using callbyname in vb.net to call another function with arguments. But the arguments order is only known in runtime. So I want to define the argument by it's name, not the position in the args array.
Private Sub mainSub()
Dim argArr as Object()
ReDim Preserve argArr(1)
argArr(0) = "argTwo:= "Argument Two""
argArr(1) = "argOne:= "Argument One""
callbyname(auxSub, CallType.Method, argArr)
End Sub
Private Sub auxSub(ByVal argOne as String, ByVal argTwo as String)
MsgBox("First Argument = " & argOne)
MsgBox("Second Argument = " & argTwo)
End Sub
In this example the messagebox would show the following messages:
First Argument - argTwo:= "Argument Two"
Second Argument - argOne:= "Argument One"
Instead of:
First Argument - Argument One
Second Argument - Argument Two
One possibly nasty way of doing this would be for your function to use a dictionary of argument names as the key and assign values from the argArr. If you're just using a one type of value e.g string values as in your example and the number of possible arguments is reasonably small, you could do it like the example below, but anything more complicated and as Hans said, you'd need to muck about with reflection.
Private Sub mainSub()
Dim argArr As Object()
ReDim Preserve argArr(1)
argArr(0) = "argTwo:= ""Argument Two"""
argArr(1) = "argOne:= ""Argument One"""
auxSub(argArr)
End Sub
Private Sub auxSub(argArray() As String)
'define a dictionary of arguments and add valid argument names
Dim ArgumentList As New Dictionary(Of String, String)
ArgumentList.Add("argOne", "")
ArgumentList.Add("argTwo", "")
'Iterate through the argument array and assign the appropriate value to its matching dictionary key
For Each arg As String In argArray
ArgumentList(Split(arg, " := ")(0)) = Split(arg, " := ")(1)
Next
End Sub
You would of course need more code to check that the argument names are valid of course.

VBA "Type mismatch: array or user-defined type expected” on String Arrays

I have a dynamic array of strings DMAs which I declare globally.
Dim DMAs() As String
I ReDim the array and assign values to it in the CreateArrayOf function which is of type String() that returns an array of type String()
DMAs = CreateArrayOf(Sites, 2, "", False)
Public Function CreateArrayOf( _
ByRef arrayFrom() As String, _
Optional ByVal numOfChars As Integer = 2, _
Optional ByVal filterChar As String = "", _
Optional ByVal filterCharIsInteger As Boolean = False _
) As String()
Dim i As Integer, _
j As Integer, _
strn As Variant, _
switch As Boolean, _
strArray() As String
'numOfChars 2 for DMA with no filterChar
'numOfChars 3 for W with filterChar "W"
'numOfChars 3 for A with filterChar "A"
'numofChars 2 for D with filterChar "D"
ReDim strArray(LBound(arrayFrom) To LBound(arrayFrom)) 'required in order to
'not throw error on first iteration
For i = LBound(arrayFrom) To UBound(arrayFrom) 'iterate through each site
switch = False
For Each strn In strArray 'iterate through the array to find whether the
'current site already exists
If strn = Mid(arrayFrom(i), 1, numOfChars) And Not strn = "" Then
switch = True
End If
Next strn
If switch = False Then 'if it doesn't exist add it to the array
ReDim Preserve strArray(1 To UBound(strArray) + 1)
strArray(UBound(strArray) - 1) = Mid(arrayFrom(i), 1, numOfChars)
End If
Next i
CreateArrayOf = strArray 'return the new array
End Function
When I attempt to pass the DMAs array to another function OutputAnArray
Private Sub OutputAnArray(ByRef arrayToOutput() As String)
Dim i As Variant
Dim x As Integer
x = 1
For Each i In arrayToOutput
Cells(x, 6).Value = i
x = x + 1
Next i
End Sub
I get the "Type mismatch: array or user-defined type expected". Throughout the whole process I only mess with string arrays.
If I take the content of the OutputAnArray function and put it in the parent function where I'm calling it from, everything's fine.
Any help is appreciated.
I changed all String definitions to Variants
Private Sub OutputAnArray(ByRef arrayToOutput() As Variant)
The culprit was still there, so then after a whole lot of attempts to get this to compile, I removed the () from the arrayToOutput parameter and it started working.
Private Sub OutputAnArray(ByRef arrayToOutput As Variant) 'fixed
What is still perplexing is the fact that in the following function definition, the () are needed for arrayFrom.
Public Function CreateArrayOf(ByRef arrayFrom() As Variant, _ ...
I really don't get it, if anyone has any idea of an explanation, I'd love to hear it.
From the documentation:
"Arrays of any type can't be returned, but a Variant containing an array can."
If follows that the function "CreateArrayOf" does not return an array of strings: it returns a variant containing an array of strings.
The variant cannot be passed as a parameter to a function expecting an array of strings:
Private Sub OutputAnArray(ByRef arrayToOutput() As String)
It can only be passed to a function expecting a variant:
Private Sub OutputAnArray(ByRef arrayToOutput as Variant)
Conversely, DMA is an array of strings:
Dim DMAs() As String
DMA can be passed to a function expecting an array of strings:
Public Function CreateArrayOf(ByRef arrayFrom() As String, _ .
And finally, "Type mismatch: array or user-defined type expected" is a generic type mismatch message. When you pass an array of the wrong type, or a variant array, and get the error "array expected", it's not particularly helpful.
There is no problem with returning typed arrays from functions or passing typed arrays to functions as arguments. The following works as expected:
Option Explicit
Sub asdfasf()
Dim DMAs() As String
DMAs = CreateAnArray()
OutputAnArray DMAs
End Sub
Private Function CreateAnArray() As String()
Dim arr() As String
ReDim arr(1 To 5)
Dim i As Long
For i = LBound(arr) To UBound(arr)
arr(i) = i
Next
CreateAnArray = arr
End Function
Private Sub OutputAnArray(ByRef arrayToOutput() As String)
Dim i As Long
For i = LBound(arrayToOutput) To UBound(arrayToOutput)
Debug.Print arrayToOutput(i)
Next
End Sub
Now, you never show how you actually pass the DMAs array to OutputAnArray.
I'm willing to make an educated guess that you are doing
OutputAnArray (DMAs)
which will indeed result in
Type mismatch: array or user-defined type expected
You cannot freely put parentheses in that manner. They have special meaning.
If you want parentheses to be used when calling a sub, you must use Call:
Call OutputAnArray(DMAs)
And if you don't care, omit the parentheses like in the example above:
OutputAnArray DMAs
I had the same error while passing an array (of user defined type) as an argument to a function ByRef.
In my case the problem was solved using the keyword "Call" in front of the function or the sub being called.
I don't really understand it, but to me it seems like VBA is trying to interpret the function/sub a couple of different ways in the absence of "Call" - which leads to the error message.
I personally try to avoid converting anything to a variant as long as possible.

Unique permutation in c# gives no dup but vb.net does

So I am converting an extension method to find permutations of a generic list from c# to vb
The code in c# does not return duplicate. For example: {1,2} is same as {2,1} and {1,1} is not allowed. The vb code that I convert, however gives me a duplicate. Can someone help me spot the problem. I got the c# code from accepted answer in this thread: How to Generate Combinations of Elements of a List<T> in .NET 4.0
Here is the vb code:
Module HelperPermutation
<Extension()>
Public Function Combinations(Of T)(elements As IEnumerable(Of T), k As Integer) As IEnumerable(Of T())
Dim result As List(Of T()) = New List(Of T())
If (k = 0) Then
result.Add(New T(-1) {})
Else
Dim current As Integer = 1
For Each element In elements
result.AddRange(elements _
.Skip(current = current + 1) _
.Combinations(k - 1) _
.Select(Function(c) (New T() {element}).Concat(c).ToArray())
)
Next
End If
Return result
End Function
End module
I tried to add Distinct but it still gives me duplicates.
And this is my console app to use that extension method:
Dim list As New List(Of Integer) From {1, 2, 3}
Dim array = list.Combinations(2)
Console.WriteLine("# of permutation: " & array.Count)
For Each value In array
Console.WriteLine("-------Pairs: " & value.Count)
For i As Integer = 0 To value.Count - 1 Step 1
Console.WriteLine("value = " & value.ElementAt(i))
Next
Next
Console.ReadLine()
current = current + 1 is not doing assignment. It's an equality test, so the result of that expression is boolean. Since there is no overload for Skip() that takes a boolean, it seems like you might not be using Option Strict. I would highly suggest using it for spotting mistakes like this.
There is no post-increment built into the VB language, but luckily, you can create your own.
Function PostIncrement(ByRef arg As Integer) As Integer
arg += 1
Return arg - 1
End Function

handling dbnull data in vb.net

I want to generate some formatted output of data retrieved from an MS-Access database and stored in a DataTable object/variable, myDataTable. However, some of the fields in myDataTable cotain dbNull data. So, the following VB.net code snippet will give errors if the value of any of the fields lastname, intials, or sID is dbNull.
dim myDataTable as DataTable
dim tmpStr as String
dim sID as Integer = 1
...
myDataTable = myTableAdapter.GetData() ' Reads the data from MS-Access table
...
For Each myItem As DataRow In myDataTable.Rows
tmpStr = nameItem("lastname") + " " + nameItem("initials")
If myItem("sID")=sID Then
' Do something
End If
' print tmpStr
Next
So, how do i get the above code to work when the fields may contain dbNull without having to check each time if the data is dbNull as in this question?
The only way that i know of is to test for it, you can do a combined if though to make it easy.
If NOT IsDbNull(myItem("sID")) AndAlso myItem("sID") = sId Then
'Do success
ELSE
'Failure
End If
I wrote in VB as that is what it looks like you need, even though you mixed languages.
Edit
Cleaned up to use IsDbNull to make it more readable
I got tired of dealing with this problem so I wrote a NotNull() function to help me out.
Public Shared Function NotNull(Of T)(ByVal Value As T, ByVal DefaultValue As T) As T
If Value Is Nothing OrElse IsDBNull(Value) Then
Return DefaultValue
Else
Return Value
End If
End Function
Usage:
If NotNull(myItem("sID"), "") = sID Then
' Do something
End If
My NotNull() function has gone through a couple of overhauls over the years. Prior to Generics, I simply specified everything as an Object. But I much prefer the Generic version.
You can also use the Convert.ToString() and Convert.ToInteger() methods to convert items with DB null effectivly.
A variation on Steve Wortham's code, to be used nominally with nullable types:
Private Shared Function GetNullable(Of T)(dataobj As Object) As T
If Convert.IsDBNull(dataobj) Then
Return Nothing
Else
Return CType(dataobj, T)
End If
End Function
e.g.
mynullable = GetNullable(Of Integer?)(myobj)
You can then query mynullable (e.g., mynullable.HasValue)
Microsoft came up with DBNull in .NET 1.0 to represent database NULL. However, it's a pain in the behind to use because you can't create a strongly-typed variable to store a genuine value or null. Microsoft sort of solved that problem in .NET 2.0 with nullable types. However, you are still stuck with large chunks of API that use DBNull, and they can't be changed.
Just a suggestion, but what I normally do is this:
All variables containing data read from or written to a database should be able to handle null values. For value types, this means making them Nullable(Of T). For reference types (String and Byte()), this means allowing the value to be Nothing.
Write a set of functions to convert back and forth between "object that may contain DBNull" and "nullable .NET variable". Wrap all calls to DBNull-style APIs in these functions, then pretend that DBNull doesn't exist.
You can use the IsDbNull function:
If IsDbNull(myItem("sID")) = False AndAlso myItem("sID")==sID Then
// Do something
End If
If you are using a BLL/DAL setup try the iif when reading into the object in the DAL
While reader.Read()
colDropdownListNames.Add(New DDLItem( _
CType(reader("rid"), Integer), _
CType(reader("Item_Status"), String), _
CType(reader("Text_Show"), String), _
CType( IIf(IsDBNull(reader("Text_Use")), "", reader("Text_Use")) , String), _
CType(reader("Text_SystemOnly"), String), _
CType(reader("Parent_rid"), Integer)))
End While
For the rows containing strings, I can convert them to strings as in changing
tmpStr = nameItem("lastname") + " " + nameItem("initials")
to
tmpStr = myItem("lastname").toString + " " + myItem("intials").toString
For the comparison in the if statement myItem("sID")=sID, it needs to be change to
myItem("sID").Equals(sID)
Then the code will run without any runtime errors due to vbNull data.
VB.Net
========
Dim da As New SqlDataAdapter
Dim dt As New DataTable
Call conecDB() 'Connection to Database
da.SelectCommand = New SqlCommand("select max(RefNo) from BaseData", connDB)
da.Fill(dt)
If dt.Rows.Count > 0 And Convert.ToString(dt.Rows(0).Item(0)) = "" Then
MsgBox("datbase is null")
ElseIf dt.Rows.Count > 0 And Convert.ToString(dt.Rows(0).Item(0)) <> "" Then
MsgBox("datbase have value")
End If
I think this should be much easier to use:
select ISNULL(sum(field),0) from tablename
Copied from: http://www.codeproject.com/Questions/736515/How-do-I-avoide-Conversion-from-type-DBNull-to-typ
Hello Friends
This is the shortest method to check db Null in DataGrid and convert to string
create the cell validating event and write this code
If Convert.ToString(dgv.CurrentCell.Value) = "" Then
CurrentCell.Value = ""
End If
This is BY FAR the easiest way to convert DBNull to a string.
The trick is that you CANNOT use the TRIM function (which was my initial problem) when referring to the fields from the database:
BEFORE (produced error msg):
Me.txtProvNum.Text = IIf(Convert.IsDBNull(TRIM(myReader("Prov_Num"))), "", TRIM(myReader("Prov_Num")))
AFTER (no more error msg :-) ):
Me.txtProvNum.Text = IIf(Convert.IsDBNull(myReader("Prov_Num")), "", myReader("Prov_Num"))
Simple, but not obvious.
DbNull.Value.Equals(myValue)
I hate VB.NET
For your problem, you can use following special workaround coding that only exists in VB.Net.
Dim nId As Integer = dr("id") + "0"
This code will replace DBNull value contained in id column by integer 0.
The only acceptable default value is "0" because this expression must also be used when dr("id") is not NULL !
So, using this technic, your code would be
Dim myDataTable as DataTable
Dim s as String
Dim sID as Integer = 1
...
myDataTable = myTableAdapter.GetData() ' Reads the data from MS-Access table
...
For Each myItem As DataRow In myDataTable.Rows
s = nameItem("lastname") + " " + nameItem("initials")
If myItem("sID") + "0" = sID Then
' Do something
End If
Next
I have tested this solution and it works on my PC on Visual Studio 2022.
PS: if sID can be equal to 0 and you want to do something distinct when dr("sID") value is NULL, you must also adept you program and perhaps use Extension as proposed at end of this answer.
I have tested following statements
Dim iNo1 As Integer = dr("numero") + "0"
Dim iNo2 As Integer = dr("numero") & "0" '-> iNo = 10 when dr() = 1
Dim iNo3 As Integer = dr("numero") + "4" '-> iNo = 5 when dr() = 1
Dim iNo4 As Integer = dr("numero") & "4" '-> iNo = 14 when dr() = 1
Dim iNo5 As Integer = dr("numero") + "" -> System.InvalidCastException : 'La conversion de la chaîne "" en type 'Integer' n'est pas valide.'
Dim iNo6 As Integer = dr("numero") & "" -> System.InvalidCastException : 'La conversion de la chaîne "" en type 'Integer' n'est pas valide.'
Dim iNo7 As Integer = "" + dr("numero") -> System.InvalidCastException : 'La conversion de la chaîne "" en type 'Integer' n'est pas valide.'
Dim iNo8 As Integer = "" & dr("numero") -> System.InvalidCastException : 'La conversion de la chaîne "" en type 'Integer' n'est pas valide.'
Dim iNo9 As Integer = "0" + dr("numero")
Dim iNo0 As Integer = "0" & dr("numero")
Following statements works also correctly
Dim iNo9 As Integer = "0" + dr("numero")
Dim iNo0 As Integer = "0" & dr("numero")
I recognize that is a little tricky.
If trick are not your tips, you can also define an Extension so that following code works.
Dim iNo = dr.GetInteger("numero",0)
where GetInteger() code can be following
Module Extension
'***********************************************************************
'* GetString()
'***********************************************************************
<Extension()>
Public Function GetString(ByRef rd As SqlDataReader, ByRef sName As String, Optional ByVal sDefault As String = "") As String
Return GetString(rd, rd.GetOrdinal(sName), sDefault)
End Function
<Extension()>
Public Function GetString(ByRef rd As SqlDataReader, ByVal iCol As Integer, Optional ByVal sDefault As String = "") As String
If rd.IsDBNull(iCol) Then
Return sDefault
Else
Return rd.Item(iCol).ToString()
End If
End Function
'***********************************************************************
'* GetInteger()
'***********************************************************************
<Extension()>
Public Function GetInteger(ByRef rd As SqlDataReader, ByRef sName As String, Optional ByVal iDefault As Integer = -1) As Integer
Return GetInteger(rd, rd.GetOrdinal(sName), iDefault)
End Function
<Extension()>
Public Function GetInteger(ByRef rd As SqlDataReader, ByVal iCol As Integer, Optional ByVal iDefault As Integer = -1) As Integer
If rd.IsDBNull(iCol) Then
Return iDefault
Else
Return rd.Item(iCol)
End If
End Function
End Module
These methods are more explicitely and less tricky.
In addition, it is possible to define default values other than ZERO and also specific version as GetBoolean() or GetDate(), etc ...
Another possibility is to report SQL default conversion in SQL command using COALESCE SQL command !