I (new to VB.NET) am doing some code maintenance on a function that sometimes throws an exception "error converting string "False" (or "True") to type Integer." What I found was something equivalent to this
someVal is a string, someFun1 returns an Integer and someFun2 takes an Integer as a parameter
...
someVal = someVal = someFun1()
...
someFun2(someVal)
...
What I think might be happening is that it is trying to assign someFun1's return value into someVal, then perform a bool check as to whether someVal has changed - but I don't think that is what needs to be done.
My question is - does this double assignment (someVal = someVal = someFun1()) accomplish anything that I don't know about in VB.NET?
another note: I realize there are implicit casts of integer to string and back to integer, but that shouldn't be causing any problems, because the values should always hold a numerical value (which can be implicitly cast back and forth from Integer and String, right?) not True or False - as far as I can tell
The confusion here is that the equals operator = is the same as the assignment operator = in VB.NET. In C#, the code above would be equivalent to
someVal = someVal == someFun1();
where the boolean equals operator == is carried out first, and the result is inserted into someVal. This fails, because someVal is int, not bool.
In other words, the runtime is comparing someVal with the return value of someFun1(), returning True or False, and failing to cast that to an integer. This isn't a "double assignment" - it's just an inline representation of
If someVal = someFun1() Then
someVal = True
Else
someVal = False
End If
where it is much more obvious that we're trying to give an Integer variable a value of type Boolean.
Related
Coming from Basic boolean logic in C#, I was wondering why:
Dim b As Boolean
Dim obj As Object = Nothing
'followig evaluates to False'
b = DirectCast(Nothing, Boolean)
'This throws an "Object reference not set to an instance of an object"-Exception'
b = DirectCast(obj, Boolean)
A CType(obj, Boolean) would evaluate to False(just as CBool(obj)). I think it is because the compiler uses a helper function, but that is not my theme.
Why does casting Nothing to Boolean evaluates to False, whereas casting an object that is Nothing to Boolean throws an Nullreference-Exception? Does that make sense?
[Option Strict ON]
Presumably, this is because Nothing in VB.NET is not exactly the same thing as null in C#.
In the case of value types, Nothing implies the default value of that type. In the case of a Boolean, the default value is False, so the cast succeeds.
One of the primary differences between value types such as Integer or structures and reference types such as Form or String is that reference types support a null value. That is to say, a reference type variable can contain the value Nothing, which means that the variable doesn't actually refer to a value. In contrast, a value type variable always contains a value. An Integer variable always contains a number, even if that number is zero. If you assign the value Nothing to a value type variable, the value type variable just gets assigned its default value (in the case of Integer, that default value is zero). There is no way in the current CLR to look at an Integer variable and determine whether it has never been assigned a value - the fact that it contains zero doesn't necessarily mean that it hasn't been assigned a value.
–The Truth about Nullable Types and VB...
EDIT: For further clarification, the reason the second example throws a NullReferenceException at run-time is because the CLR is attempting to unbox the Object (a reference type) to a Boolean. This fails, of course, because the object was initialized with a null reference (setting it equal to Nothing):
Dim obj As Object = Nothing
Remember that, as I explained above, the VB.NET keyword Nothing still works the same way as null in C# when it comes to reference types. That explains why you're getting a NullReferenceException because the object you're attempting to cast is literally a null reference. It does not contain a value at all, and therefore cannot be unboxed to a Boolean type.
You don't see the same behavior when you try to cast the keyword Nothing to a Boolean, i.e.:
Dim b As Boolean = DirectCast(Nothing, Boolean)
because the keyword Nothing (this time, in the case of value types) simply means "the default value of this type". In the case of a Boolean, that's False, so the cast is logical and straightforward.
There's a couple of things you have to realize here.
The first is what others have already pointed out: Nothing can be interpreted by the VB compiler as simply the Boolean value False given the proper context, such as Dim b As Boolean = Nothing.
This means that when the compiler sees this:
b = DirectCast(Nothing, Boolean)
It sees a literal (Nothing) and also sees that you want to use this literal as a Boolean. That makes it a no-brainer.
But now here's the second thing you have to realize. DirectCast on an Object is essentially an unboxing operation (for value types). So what needs to happen from the VB compiler's perspective is: there needs to be a Boolean in that box, or else the operation will fail. Since there is in fact nothing in the box—and this time we're really talking nothing, as in null—it throws an exception.
If I were to translate this code to C#, it would look like this:
bool b;
object obj = null;
b = (bool)default(bool);
b = (bool)obj;
Hopefully that makes things a bit clearer?
There's a difference between using the keyword (literal) Nothing, and using a reference variable whose value is Nothing.
In VB.NET, the literal (keyword) Nothing gets special treatment. The Nothing keyword can be automatically converted into a value type, using the default value of that type.
A reference variable whose value is Nothing is different. You don't get the special behaviour.
The documentation says DirectCast "requires an inheritance or implementation relationship between the data types of the two arguments".
Clearly Object does not inherit from or implement Boolean, unless you have put a boxed Boolean into an object variable.
So the code below fails at runtime with an exception.
Dim obj As Object = Nothing
b = DirectCast(obj, Boolean)
To get the expected behavior, you need this code:
Dim b As Boolean?
Dim obj As Object = Nothing
b = DirectCast(obj, Boolean?)
The character ? mean Nullable(of ).
I'm finding that comparing of the Boolean variable to a string of "True", "False" or Is nothing seems to ensure that I get the correct comparisons. I was using a function to return an html string of a div with an image of a checked or unchecked radio button and was having the issue of nothing coming back as false. Using the variable = "True" or "False" string and doing the last check with IS NOTHING helped to resolve that issue.
Dim b as boolean = nothing
response.write CheckValue(b = "True")
response.write (b = "False")
response.write (b is nothing)
Function CheckValue(inVal as boolean) as string
if inVal then
return ("<div><img src="checked.png" ></div>
else
return ("<div><img src="unchecked.png" ></div>
end if
end function
The system seems to do the conversion to string when implicitly compared to a string whereas using the .tostring method just creates an error while allowing the last comparison to actually compare to a value of nothing.
Hopefully that helps somewhat. It at least let me
Suppose I want to use an If statement, but I won't know until run-time what the actual condition of the If statement will be. Is there a way to do this by passing the condition as the contents of a string? As an example of the kind of thing I'm looking to acheive, consider the following bit of code;
Dim a as Integer = 1
Dim b as Integer = 2
Dim ConditionString As String = "<"
If a ConditionString b Then
...
End If
Mainly what I'm looking for is some way to leave the actual condition undefined until run-time. The reason I want to do this is because I need to have a set of threshold conditions in a database including not just the numeric values themselves, but also comparison operations. I might want to have something that amounts to "> 3.2 And < 5.6". As numbers are pulled in from data, the comparison operations need to be applied to the data depending on various conditions. Also, the database would be changed from time-to-time.
For such cases I love to use NCalc library, it has everything you need - it parses simple expressions (including logical and relational). Here is an example of it in C#:
var expr = new Expression("[X] > 3.2 and [X] < 5.6");
expr.Parameters["X"] = 10.0;
if (expr.Evaluate())
{
// ...
}
and VB.NET:
Dim expr As var = New Expression("[X] > 3.2 and [X] < 5.6")
expr.Parameters("X") = 10
If expr.Evaluate Then
' ...
End If
You can store a map of String to Func(Of Integer, Integer, Boolean) keyed by the strings "<", ">", "==", and so on, and take addresses of the functions that implement those conditions. For example:
Function LessThan(Integer a, Integer b) As Boolean
Return a < b
End Function
Dim Comparisons As New Map(Of String, Func(Of Integer, Integer, Boolean))
Comparisons.Add("<", AddressOf LessThan)
And then you can call it as such:
Dim a as Integer = 1
Dim b as Integer = 2
Dim ConditionString As String = "<"
If Comparisons(ConditionString)(a, b) Then
There are only a few possible conditions so I would just use a Select..Case statement:
Select Case ConditionString
Case "<"
Case ">"
'etc.
Case Else
End Select
Otherwise, you cannot (simply) convert a string "<" to an operator.
You just need a 'code', mapping some kind of value that you can store in a database to the various kinds of "conditions" you wish to test. Instead of a string, I'd suggest using an enum:
Enum ConditionEnum
LessThan
GreaterThan
Equal
SomeOtherVeryComplicatedBinaryFunction
End Enum
And then define a method that evaluates the condition along with the two arguments:
Public Sub EvaluateConditionWithArguments(ConditionEnum condition, Integer a, Integer b) As Boolean
EvaluateConditionWithArguments = False
Select Case condition
Case ConditionEnum.LessThan
If a < b Then
EvaluateConditionWithArguments = True
End If
...
End Select
End Sub
How to Decimal.TryParse in below line of code if value is null or empty then it should be 0 in inline coding in VB.NET
<input type="checkbox" name="ticket" id="ticket<%=y%>" title="<%=(CDec(Decimal.TryParse(late_fee)) + CDec(rs("ticket_amount")) + CDec(rs("nsf_fee")))-(CDec(rsp("TICKET_PAYMENTS")) + CDec(rsp("LATEFEE_PAYMENTS")) + CDec(rsp("NSFFEE_PAYMENTS")))%>" value="<%=rs("ticket_id")%>" checked="checked" onclick="doMath();"/>
Thanks for your advice
TryParse returns true or false based on whether conversion was successful on not.
try:
double number;
Double.TryParse(late_fee, out number);
number: "When this method returns, contains the double-precision floating-point number equivalent of the late_fee parameter, if the conversion succeeded, or zero if the conversion failed"
Use the 'number'
(CDec(number) + CDec(rs("ticket_amount")) + CDec(rs("nsf_fee")))-(CDec(rsp("TICKET_PAYMENTS")) + CDec(rsp("LATEFEE_PAYMENTS")) + CDec(rsp("NSFFEE_PAYMENTS")))
You cannot inline TryParse methods since you need to declare the variable first that will be returned from the TryParse-method. You either have to use multiple lines or create a method that returns it.
I would recommend to use variables anyway since that makes your code much more readable and that is the most important of all.
However, for what it's worth, you could make an extension which returns the decimal or a default value:
Module StringExtensions
<Runtime.CompilerServices.Extension()>
Public Function ParseDecimal(ByVal aString As String, defValue As Decimal, Optional culture As Globalization.CultureInfo = Nothing) As Decimal
Dim retVal As Decimal = defValue
If culture Is Nothing Then culture = Globalization.CultureInfo.CurrentCulture
Decimal.TryParse(aString, Globalization.NumberStyles.Any, culture, retVal)
Return retVal
End Function
End Module
Then you could inline the calculation even if i would still use multiple lines and variables to increase readability.
Dim lateFee As Decimal = late_fee.ParseDecimal(0) ' and the other variables ....
When using the If operator (http://msdn.microsoft.com/en-us/library/bb513985(v=VS.100).aspx) to assign a value to a System.Nullable object, if the result is Nothing (null), then 0 is assigned to the object.
Example:
'Expected value is null (Nothing). Actual value assigned is 0.
Dim x As System.Nullable(Of Integer) = If(1 = 0, 1, Nothing)
If x is a nullable type, why is it being assigned the default integer type of 0. Shouldn't it receive a value of null?
Nothing in the context of a value type resolves to the default value for that type. For an integer, this is just 0.
The If operator does not do any conversions between its argument types, they are all treated equally – as Integer in your case. Hence your code is the same as
Dim x As Integer? = If(1 = 0, 1, 0)
To make the result nullable, you need to make the types explicit.
Dim x As Integer? = If(1 = 0, 1, CType(Nothing, Integer?))
Rather than return Nothing cast as Integer? Just create a new Integer? and return it.
Also, keep in mind when working with Nullable types, you should always use the .Value, .HasValue and .GetValueOrDefault methods on Nullable(Of T) rather than just returning the object. Thus in your case, the Value of X is indeed 0, but if you check the HasValue property it should return False to indicate the null situation. Similarly, if you want to check If x = Nothing, it will return False, but If x.HasValue = False returns True.
You could also write your example as follows which works correctly:
Dim x as Integer? = If(1=0, 1, new Integer?)
Console.WriteLine(x)
Console.WriteLine(x.HasValue)
Outputs:
null
False
I am trying to write a generic function that will check each database parameter to see if it is null, and if so, return DBNull; if not, return the object.
So here is my function:
Public Shared Function CheckForNull(ByVal obj As Object) As Object
If obj <> Nothing Then Return obj Else Return DBNull.Value
End Function
My problem is that some of the objects I am passing to the function are Nullable. So I may pass the function a Long? or Int?, but when a nullable type is passed to the function, it is converted to its value type. So if I pass a Long? that has a value of 0, the function returns DBNull because the Long? is converted to Long and a value of 0 for a Long is equivalent to Nothing. Is there anyway to make this function work for Nullable types as well?
If not, I will just fall back to using the following statements instead of one generic funciton call:
IIf(nullableVar.HasValue, nullableVar, DBNull.Value))
and
IIf(nonNullableVar IsNot Nothing , nonNullableVar, DBNull.Value))
That is not why your logic is failing. When evaluating an expression like (x=y) or (x<>y), if either argument is Nothing, VB.Net returns FALSE. Your conditional is always falling through to the ELSE clause. So instead of:
if obj <> Nothing then
try this instead:
if obj isnot nothing then