I can't understand what is happening with the following code in VB.NET. When I run this code:
Public Function test() As Boolean
Dim a As Integer = 1
Dim b As Object = a
Dim c As Object = b
Return Object.ReferenceEquals(b, c)
End Function
Then the function returns True. However, if I run this:
Structure TTest
Dim i As Integer
Dim tid As Integer
Sub New(ByVal _i As Integer, ByVal _tid As Integer)
i = _i
tid = _tid
End Sub
End Structure
Public Function test_2() As Boolean
Dim a As New TTest(1, 1)
Dim b As Object = a
Dim c As Object = b
Return Object.ReferenceEquals(b, c)
End Function
Then it returns False. In both functions, I declare two value type variables, an Integer on the first and a custom Structure on the second one. Both should be boxed upon object assignment, but in the second example, it seems to get boxed into two different objects, so Object.ReferenceEquals returns False.
Why does it work this way?
For primitive types, .Net is able to re-use the same "box" for the same values, and thus improve performance by reducing allocations.
Same with strings, it's .NET way to optimize thing. But as soon as you use it, the reference will change.
Sub Main()
Dim a As String = "abc"
Dim b As String = "abc"
Console.WriteLine(Object.ReferenceEquals(a, b)) ' True
b = "123"
Console.WriteLine(Object.ReferenceEquals(a, b)) ' False
Console.ReadLine()
End Sub
I'm using vb.net. I am doing some checking and scrubbing of my data when i get it from the database. I'm using an overload but it doesn't seem to be working for decimal numbers. Decimal numbers get treated as integers.
Public Class CheckData
Public Shared Function Check(row As DataRow, columnName As String, pDefaultValue As Decimal) As Decimal
Dim x As Object = ReplaceDBNullAndColumnExists(row, columnName)
Dim y As Decimal = CDec(Dempsey.fnIsNull.IsNull(x, pDefaultValue))
Return y
End Function
Public Shared Function Check(row As DataRow, columnName As String, pDefaultValue As DateTime) As DateTime
Dim x As Object = ReplaceDBNullAndColumnExists(row, columnName)
Dim y As DateTime = Dempsey.fnIsNull.IsNull(x, pDefaultValue)
Return y
End Function
Public Shared Function Check(row As DataRow, columnName As String, pDefaultValue As Integer) As Integer
Dim x As Object = ReplaceDBNullAndColumnExists(row, columnName)
Dim y As Integer = Dempsey.fnIsNull.IsNull(x, pDefaultValue)
Return y
End Function
Public Shared Function Check(row As DataRow, columnName As String, pDefaultValue As String) As String
Dim x As Object = ReplaceDBNullAndColumnExists(row, columnName)
Dim y As String = Dempsey.fnIsNull.IsNull(x, pDefaultValue)
Return y
End Function
Public Shared Function Check(row As DataRow, columnName As String, pDefaultValue As Boolean) As Boolean
Dim x As Object = ReplaceDBNullAndColumnExists(row, columnName)
Dim y As Boolean = Dempsey.fnIsNull.IsNull(x, pDefaultValue)
Return y
End Function
So if i pass in some data and the type is a string, integer, boolean or datetime it goes to the propert function. if i pass in a decimal it goes to integer. If i set a breakpoint on the public shared function check that is a integer function and do a
row.Table.Columns(columnName).DataType.Name
I get back - "Decimal" (doing this in the immediate window)
So my question is what have i done wrong that it doesn't take it to the decimal overload and return a decimal value. By the way, the actual data value is 37.50.
Thanks
shannon
I use this to populate list.
Public Function populate(mDs As DataSet) As List(Of SR_SalaryRange_Current)
Dim rows As DataRowCollection
Dim drow As DataRow
Dim oSR_SalaryRange_Current As SR_SalaryRange_Current
Dim oSR_SalaryRange_Currents As List(Of SR_SalaryRange_Current) = New List(Of SR_SalaryRange_Current)
Dim dt As New DataTable
Try
dt = mDs.Tables("SR_SalaryRange_Currents")
rows = dt.Rows
For Each drow In rows
oSR_SalaryRange_Current = New SR_SalaryRange_Current
With oSR_SalaryRange_Current
.tblSR_SalaryRange_CurrentID = SitePlumbing.CheckData.Check(drow, "intTblSR_SalaryRange_CurrentID", 0)
.EffectiveDate = SitePlumbing.CheckData.Check(drow, "dtmEffectiveDate", CDate("1/1/1900"))
.WorkWeekHours = SitePlumbing.CheckData.Check(drow, "decWorkWeekHours", 0)
End With
oSR_SalaryRange_Currents.Add(oSR_SalaryRange_Current)
Next
Catch ex As Exception
ErrorMsg = "Populate Error:" & ex.InnerException.ToString
Return oSR_SalaryRange_Currents
End Try
Return oSR_SalaryRange_Currents
End Function
from there it goes into the checkdata that i mentioned before. In the code above it correctly goes to an integer and a datetime when hitting the overload, just isn't doing it for the decimal.
A decimal is implicitly covertable into an integer so the compiler is confused if you have OPTION STRICT set to off. You have two options:
1) Set OPTION STRICT to ON. Then the compiler will not convert implicitly.
2) Pass in a decimal literal like this: 10D (i.e. there is a D on the end telling the compiler it is a decimal).
For example:
'Sub Routine 1
public sub Test(ByVal d as decimal)
end sub
'Sub Routine 2
public sub Test(ByVal i as integer)
end sub
//Client
dim d1 as decimal={Number}D 'where {number} is replaced with a number
dim d2 as decimal={Number} 'where {number} is replaced with a number
Test(d1) 'this will always go to Sub Routine 1 regardless of whether OPTION strict is ON or OFF
Test(d2) 'this will go to Sub Routine 1 if option strict is ON. If it is OFF, then it may go to Sub Routine 2 depending on the size of the number.
I was given a way to work with this by Viorel on another forum. He suggested I do
Check(drow, "decWorkWeekHours", 0#)
and that did indeed work. When i asked what it does, this was his response.
With ‘#’, the constant ‘0#’ becomes a decimal one. Then VB.NET chooses the definition of Check that takes a Decimal parameter, since it is more suitable comparing with other candidates.
You can also write ‘0d’ [https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/data-types/type-characters].
hope that will help someone else down the road.
Thanks
shannon
.. eg: have a stri ng
strResult="controlName1.value * controlName2.value"
.. I need to change it to just controlName1.value * controlName2.value so that i can get the output as double value
Please reply
Thanks
If you're using Windows Forms, there is an indexer property that accepts the name of a sub-control as a string and returns the control if a match is found. See: Control.ControlCollection.Item Property (String).aspx
The straightforward alternative in all UI frameworks is to map Strings to Controls like such:
Function MapStringToControl(ctlName As String) As Control
Select Case ctlName
Case "controlName1"
Return controlName1
Case "controlName2"
Return controlName2
Case Else
Return Nothing
End Function
Of course note that there is no .Value property in Windows Forms--you need to do something like Integer.Parse(ctl.Text).
It depends what type of control it is. For example a textbox has a .Text property. A NumericUpDown control has a .Value property.
All you need to do is to convert the appropriate property to the appropriate type. So for TextBoxes:
Dim result as Double = CDbl(txtFoo.Text) * CDbl(txtBar.Text)
For a NumericUpDown:
Dim result as Double = CDbl(nudFoo.Value) * CDbl(numBar.Value)
Hi guys thanks for your updates.. I wrote my own function by using your concepts and some other code snippets .I am posting the result
Function generate(ByVal alg As String, ByVal intRow As Integer) As String
Dim algSplit As String() = alg.Split(" "c)
For index As Int32 = 0 To algSplit.Length - 1
'algSplit(index) = algSplit(index).Replace("#"c, "Number")
If algSplit(index).Contains("[") Then
Dim i As Integer = algSplit(index).IndexOf("[")
Dim f As String = algSplit(index).Substring(i + 1, algSplit(index).IndexOf("]", i + 1) - i - 1)
Dim grdCell As Infragistics.Win.UltraWinGrid.UltraGridCell = dgExcelEstimate.Rows(intRow).Cells(f)
Dim dblVal As Double = grdCell.Value
algSplit(index) = dblVal
End If
Next
Dim result As String = String.Join("", algSplit)
'Dim dblRes As Double = Convert.ToDouble(result)
Return result
End Function
Thanks again every one.. expecting same in future
why I only get "0" back? My Code:
Dim GeldAdresse As String = "811768"
Dim offsets(1) As Integer
offsets = {&H28, &H2C}
Dim ergebniss As Integer = Memory.ReadPointerInteger("eurotrucks2", 811768, offsets)
The Module "Memory":
Public Function ReadPointerInteger(ByVal EXENAME As String, ByVal Pointer As Integer, ByVal ParamArray Offset As Integer()) As Integer
Dim Value As Integer
If Process.GetProcessesByName(EXENAME).Length <> 0 Then
Dim Handle As Integer = Process.GetProcessesByName(EXENAME)(0).Handle
If Handle <> 0 Then
For Each I As Integer In Offset
ReadMemoryInteger(Handle, Pointer, Pointer)
Pointer += I
Next
ReadMemoryInteger(Handle, Pointer, Value)
End If
End If
Return Value
End Function
In the Example:
' Me.Text = ReadPointerInteger("gta_sa", &HB71A38,&H540,&H544).ToString()
Must I convert 0x2C in a Integer?
Dim Value As Integer
...
Return Value
You are returning Value but never assing a real value to it. Looks like you need to change your code to:
Dim Value As Integer
...
Value = ReadMemoryInteger(...
...
Return Value
The class is broken. I use antoher.
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 !