How to really check if something is null in VB.NET? - asp.net

I have an entity with a NrPeso decimal property that can be saved in the database as 0 or null.
Here is what I'm doing to assign the value to the property:
entity.NrPeso = Convert.ToDecimal(object.value("value"))
The problem is: if I don't fill the object value, it's set to Nothing. When I do the cast it turns into 0. But I don't want 0, I want Nothing. If I compare the object value with Nothing it will return me Nothing if it is Nothing or 0.
I tought in a few alternatives but they don't seem good.
So, what is the right way to do this?

Decimal is a structure - is cannot be Nothing by definition.
You need a nullable Decimal.
If NrPeso is defined as Nullable(Of Decimal) (aka Decimal?), things should work as you expect.

If you want to distinguish between 0 and Nothing when using Decimal (or any other value type), you should use a nullable type in the first place.
So use Decimal? instead of Decimal

Try this:
Dim obj As Object = object.value("value")
entity.NrPeso = If (obj Is Nothing, Nothing, Convert.ToDecimal (obj))

Instead of using Convert.ToDecimal, consider using Decimal.TryParse and then in a failure condition explicitly set the Nullable type to Null:
Dim outVal As Decimal?
If Decimal.TryParse(object.value("value"), outVal)
entity.NrPeso = outVal
Else
entity.NrPeso = Nothing
End If
Additionally, consider setting Option Strict On in your project to avoid type issues like this in the future.

Related

ASP Session variables: Is "" same as IsEmpty?

In ASP an uninitialized Session variable Is Empty. I know that the correct way to check for a Session value, and remove a value, is the following:
IF NOT IsEmpty(Session("myVar")) THEN
' Go ahead and use Session("myVar")
...
' Now if we're all done with myVar then remove it:
Session.Contents.Remove("myVar")
END IF
I've inherited a codebase where Application and Session variables are typically set = "" after use, and all tests for a value are of the form (Sessions("myVar") = ""). This test appears to work when the Session variable has not been declared ... or maybe it's just working by dumb luck.
Is it safe to use comparison with the empty string to test for a Session variable? I.e., is the following "practically as good" as the correct method shown above?
IF Session("myVar") <> "" THEN
' Go ahead and use Session("myVar")
...
' Now if we're all done with myVar then blank it:
Session("myVar") = ""
END IF
Or should I refactor the codebase so that:
All tests to determine whether a Session variable has been set are of the form IsEmpty(Session("myVar"))
All session variables are Removed and not set = ""?
Empty is a strange beast: it is simultaneously equal to both "" and 0. Seriously, try it:
dim x, y, z
x = Empty
y = ""
z = 0
Response.Write (x = y) AND (x = z)
It'll write out "True".
This means that testing for Not IsEmpty(myvar) is equivalent to testing myvar <> "", but IsEmpty(myvar) is not equivalent to myvar = "". Whether that mostly-theoretical difference bothers you or not is something only you can answer, but personally, I wouldn't waste time on refactoring.
If you do decide to refactor, I would suggest forgetting about IsEmpty and IsNull and whatnot, and just using the & "" "hack":
If Session("myvar") & "" <> "" Then
This'll transparently handle Nulls and Empties without you needing to write a whole bunch of code.
No, it could be not safe. Perhaps you need to use functions: IsNull, IsEmpty and VarType
IsNull -- returns True if expression is Null, that is, it contains no
valid data; otherwise, IsNull returns False. If expression consists of
more than one variable, Null in any constituent variable causes True
to be returned for the entire expression.
VarType -- Returns a value indicating the subtype of a variable.
IsEmpty -- returns True if the variable is uninitialized, or is
explicitly set to Empty; otherwise, it returns False. False is always
returned if expression contains more than one variable.
Please take a look at What is the '<>' asp operator?

Regex or Try Catch to Validate Double - Best Performance

I'm having some variables passed over from the client side to the server. One of the variables should be received as a double but occasionally we get some string or null variables through from the client side that throws an exception.
My question is, from a performance aspect is it better to wrap the variable in a try, catch and apply a default on failure:
Dim expectDouble As Double
Try
expectDouble = Request.Form("pastFromClient")
Catch ex As Exception
expectDouble = 0 'Default to zero
End Try
Or to initially treat all incoming variables as string objects and run them against a regex?
Dim expectDouble As Double
If Regex.IsMatch(Request.Form("pastFromClient").toString, "^\d{1,}\.{0,1}\d{0,4}$") Then
expectDouble = Request.Form("pastFromClient")
Else
expectDouble = 0 'Default to zero
End If
The latter option may seem a little obscure but I've always felt uneasy having try, catch statements everywhere.
Probably the most important point first, you should set OPTION STRICT to ON generally. Then your code would not even copile what is a good thing.
It would not compile because Request.Form returns a string but expectDouble is a Double. A string is not convertible to double implicitely.
You should use Double.Parse or in this case Double.TryParse. Performance is not the main reason but failure safety and readability.
Dim expectDouble As Double
If Double.TryParse(Request.Form("pastFromClient"), expectDouble) Then
' here you have the value of expectDouble '
End If
Regexes are generally slow, as are Try/Catch blocks. In this case I would take the 2nd approach but I would not use Regexes.
As Tim correctly points out implicit conversion should be avoided, in this instance you can perform your operation in one line so that the following
Dim expectDouble As Double
If Regex.IsMatch(Request.Form("pastFromClient").toString, "^\d{1,}\.{0,1}\d{0,4}$") Then
expectDouble = Request.Form("pastFromClient")
Else
expectDouble = 0 'Default to zero
End If
turns into
Dim expectDouble As Double
If NOT Double.TryParse(Request.Form("pastFromClient"), expectDouble) Then expectDouble = 0
The others are correct. You want to do the casting yourself explicitly. Also, your normal program flow should never depend on an exception being caught. There's a reason they are called "exceptions".
Here's how you can do it on one line using the ternary operator:
Dim expectDouble As Double = If(Double.TryParse(Request.Form("pastFromClient"), expectDouble), expectDouble, 0)
If the value passed into the form is a valid double, then expectDouble will hold that value; otherwise, it defaults to zero. You can change the zero to some other default value if you need to.

What's wrong with groovy math?

This seems quite bizarre to me and totally putting me on the side of people willing to use plain java. While writing a groovy based app I encountered such thing:
int filesDaily1 = (item.filesDaily ==~ /^[0-9]+$/) ?
Integer.parseInt(item.filesDaily) : item.filesDaily.substring(0, item.filesDaily.indexOf('.'))
def filesDaily = (item.filesDaily ==~ /^[0-9]+$/) ?
Integer.parseInt(item.filesDaily) : item.filesDaily.substring(0, item.filesDaily.indexOf('.'))
So, knowing that item.filesDaily is a String with value '1..*' how can it possibly be, that filesDaily1 is equal to 49 and filesDaily is equal to 1?
What's more is that when trying to do something like
int numOfExpectedEntries = filesDaily * item.daysToCheck
an exception is thrown saying that
Cannot cast object '111' with class 'java.lang.String' to class 'int'
pointing to that exact line of code with multiplication. How can that happen?
You're assigning this value to an int:
item.filesDaily.substring(0, item.filesDaily.indexOf('.'))
I'm guessing that Groovy is converting the single-character string "1" into the char '1' and then taking the Unicode value in the normal char-to-int conversion... so you end up with the value 49.
If you want to parse a string as a decimal number, use Integer.parseInt instead of a built-in conversion.
The difference between filesDaily1 and filesDaily here is that you've told Groovy that filesDaily1 is meant to be an int, so it's applying a conversion to int. I suspect that filesDaily is actually the string "1" in your test case.
I suspect you really just want to change the code to something like:
String text = (item.filesDaily ==~ /^[0-9]+$/) ? items.filesDaily :
item.filesDaily.substring(0, item.filesDaily.indexOf('.'))
Integer filesDaily = text.toInteger()
This is a bug in the groovy type conversion code.
int a = '1'
int b = '11'
return different results because different converters are used. In the example a will be 49 while b will be 11. Why?
The single-character-to-int conversion (using String.charAt(0)) has a higher precedence than the integer parser.
The bad news is that this happens for all single character strings. You can even do int a = 'A' which gives you 65.
As long as you have no way of knowing how long the string is, you must use Integer.parseInt() instead of relying on the automatic type conversion.

Option Strict On disallows implicit conversions from 'String' to 'Integer'

txtAddress.Text = DB.ProfileDataset.Tables("tblCustomers").Rows.Item("Address").toString
The above code generated Option Strict On disallows implicit conversions from 'String' to 'Integer' error under the Item("Address")
I don't know what i did wrong...
The DataRowCollection.Item property requires an integer for the row index.
I think you are after the following syntax:
txtAddress.Text = DB.ProfileDataset.Tables("tblCustomers").Rows(0)("Address").ToString()
EDIT
Something to keep in mind:
original code
= DB.ProfileDataset.Tables("tblCustomers").Rows.Item("Address").toString
compiler sees
= DB.ProfileDataset.Tables.Item("tblCustomers").Rows.Item("Address").toString
fixed code
= DB.ProfileDataset.Tables("tblCustomers").Rows(0)("Address").ToString()
compiler sees
= DB.ProfileDataset.Tables.Item("tblCustomers").Rows.Item(0).Item("Address").ToString()

Question about Type Comparison ASP.NET and DBNull

I have a function that pulls articles records from an MSSQL database. Some are URLs to PDFs, and other are actual articles stored in the SQL. The articles that are stored do not have a URL (DBNull) in the record, so I want to be able to parse that. I tried a simple test:
If Row.Item("url").GetType Is GetType(DBNull) Then
//' do something here....
End If
However, I get the "Conversion from type 'DBNull' to type 'String' is not valid." exception. The funny part is, when I do a watch on the above conditional, it returns True or False.
Anyone know why this is happening and/or a way to fix this? Thanks!
I always just use this test on the record:
If IsDBNull(strSQLTiggRes("url")) Then
'Do something .
Else
'do something else
end if
Why not just use:
If Row.IsNull("url") Then
//' do something here....
End If
I like
if (DBNull.Value.Equals(Row.Item("url")))
Try
If Row.Item("url") = DBNull.Value
The error is telling you that Row.Item("url") is a System.String so the value at this point will not by DbNull.
Try something like this:
If Row.Item("url") Is Nothing Then
//' do something here....
End If
Can't you just do
If Row.Item("url") = DBNull.Value Then
End If
My preference is:
If Not Object.Equals(DBNull.Value, Row.Item("url")) Then
'Hooray!
End If
In VB, you can also use the IsDBNull function (Microsoft.VisualBasic disclaimer) directly :
If Not IsDBNull(Row.Item("url")) Then
'Hooray!
End It
Use this.
if row("ColumnName") is DBNull.value Then
'do something
end if
You will find that you must use is in this case and you nee dto compare the values not just the types. You may also want to put it into a reusable function that you can use to return nothing instead of dbnull
function checkvalue(item as object)
if item is dbnul.value then
return nothing
else
return item
end if
end function

Resources