I am trying to find the length of a control's tag to determine a Boolean's value. I've tried a couple methods to get the text length of a Tag in a control and determine if it has a length of 1 or higher, but none of them seem to be working. They all end up with a System.NullReferenceException error.
Boolean = Control.Tag.ToString.Length > 1
Boolean = Control.Tag.ToString.Count > 1
Boolean = Not Control.Tag.Equals("")
Boolean = Not Control.Tag.ToString.Equals("")
Thats because your Tag is Null (or as it's called in VB Nothing).
So before you check the length of the Tag, you need to make sure it's not Nothing. e.g with:
If Control.Tag Is Nothing Then ...
Before accessing a method or property of the tag, you must make sure that the tag is not Nothing. You can do this in a single expression by using shortcut evaluation:
Dim isDefined As Boolean = Control.Tag IsNot Nothing AndAlso Control.Tag.ToString.Length > 1
Since VB 14.0 / Visual Studio 2015 you can use a Null-conditional operator
Dim isDefined As Boolean = If(Control.Tag?.ToString.Length, 0) > 1
In VB.NET you can use VB.NET specific way as the VB Runtime evaluates Nothing as an empty string which is represented by String.Empty.
In VB.NET you can assign Nothing to any variable regardless it is a value type or a reference type.
Its C# equivalent is default(T) which for reference types returns null and for value types returns the value represented by a state where all bits are zero. E.g. default(bool) returns false
So these ways are also working:
' Let's assume you set the Control.Tag property value to this variable
Dim controlTag As Object = Nothing
' Len() method can accept any Object
Dim controlTagLength As Integer = Len(controlTag)
Dim hasValueByLength As Boolean = controlTagLength > 0
' Always call Equals() method on a constant
' or on a well defined non-null value e.g. String.Empty
' to avoid NullReferenceException
Dim hasValueByInstanceEquals As Boolean = String.Empty.Equals(controlTag)
' Or you can use the static Equals() method that accepts Object
Dim hasValueByStaticEquals As Boolean = String.Equals(controlTag, String.Empty)
Related
I can't get the code below working.
The error is in the last line: Type 'ChangeType' is not defined.
Does the compiler thinks that ChangeType is a customtype which i did't have defiened ?
I have no clue, plz give me a hint.
May be I can't see the forest for the trees.
Dim DataValue as String = "True"
Dim ChangeTypeIndex() As String = {"System.Boolean", "System.Char", "System.SByte", "System.Byte", "System.Int16"}
Dim ChangeType As Type = Type.GetType(ChangeTypeIndex(0))
Dim Result = DirectCast(DataValue, ChangeType)
This is not possible in VB.NET. VB.NET is a type-safe language, and the express purpose of DirectCast is to aid in the compile-time type checking. Since it is analyzed for correctness at compile-time, it, by definition, can't be given a variable for the type. DirectCast can only be used to cast an object to another directly-related type (by inheritance or implementation). Since DataValue is a String, you couldn't cast it to a Boolean anyway (since String doesn't inherit from Boolean), even if DirectCast did allow you to pass a variable type like that.
.NET does support reflection and late-binding, so it is possible to do the same kind of thing, if you really need to, but it's generally a good idea to avoid these kinds of things as much as you can, so as to ensure that you are getting the most benefit out of the compiler's type-checking safety measures.
Warnings aside, if you really need to do this, a close approximation would be something like this:
Option Strict Off
' ...
Dim dataValue As String = "True"
Dim changeTypeIndex() As String = {"System.Boolean", "System.Char", "System.SByte", "System.Byte", "System.Int16"}
Dim changeType As Type = Type.GetType(changeTypeIndex(0))
Dim o As Object = Activator.CreateInstance(changeType)
Dim result As Object = o.Parse(dataValue)
Console.WriteLine(result.GetType().Name) ' Outputs "Boolean"
Console.WriteLine(result) ' Outputs "True"
Not sure what you are trying to do, but here is some code to play with. Note that I have changed the 'types' in the array to contain valid type names.
Dim DataValue As String = "True"
Dim ChangeTypeIndex() As String = {"System.Boolean", "System.Char", "System.SByte", "System.Byte", "System.Int16"}
Dim ChangeType As Type
For x As Integer = 0 To ChangeTypeIndex.Length - 1
ChangeType = Type.GetType(ChangeTypeIndex(x), True)
Next
ChangeType = Type.GetType(ChangeTypeIndex(0), True)
Dim Result As Object = CTypeDynamic(DataValue, ChangeType)
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
I have following code in VB.NET:
Public Sub Test(ByRef clientId As Nullable(Of Integer))
Dim t As Object = IIf(clientId.HasValue, clientId.Value, DBNull.Value)
End Sub
The calling side pass in Nothing as clientId value, but when I run this statement I got exception.
Nullable object must have a value
Is my statement wrong?
Change it to use "If":
Dim t As Object = If(clientId.HasValue, clientId.Value, DBNull.Value)
The problem with "IIf" is that it's just a function call - all arguments are always evaluated, while the VB 'If' operator behaves like the '?' operator in C#/Java - it only evaluates what it needs to evaluate.
Dim cp As Single
' Try
If tt.getsumpaid4cors(CInt(sidtxt.Text), CInt(coidtxt.Text), CInt(tidtxt.Text), CInt(stidtxt.Text)).HasValue Then
cp = tt.getsumpaid4cors(CInt(sidtxt.Text), CInt(coidtxt.Text), CInt(tidtxt.Text), CInt(stidtxt.Text)).Value
Else
cp = 0
End If
I have a class Customer which contains the property Extensions which in turn contains the property Any.
I tried to do:
Dim room = If(customer.Extensions.Any.ElementAt(0).InnerText, Nothing)
but it threw an error when it did not find an Extension element in the incoming xml. I thought it would return nothing once it saw that the first expression was Nothing. Do I have to do a multiple if statement in this case?
Yes, you do have to check for at least one element. So what you could do would be:
Dim a = customer.Extensions.Any.FirstOrDefault()
Dim room = If(a Is Nothing, Nothing, a.InnerText)
Depending on the type of customer.Extensions.Any, you could do this:
Dim room = If(customer.Extensions.Any.Count > 0, customer.Extensions.Any(0), Nothing)
Is there a VB.NET equivalent for C#'s ?? operator?
Use the If() operator with two arguments (Microsoft documentation):
' Variable first is a nullable type.
Dim first? As Integer = 3
Dim second As Integer = 6
' Variable first <> Nothing, so its value, 3, is returned.
Console.WriteLine(If(first, second))
second = Nothing
' Variable first <> Nothing, so the value of first is returned again.
Console.WriteLine(If(first, second))
first = Nothing second = 6
' Variable first = Nothing, so 6 is returned.
Console.WriteLine(If(first, second))
The IF() operator should do the trick for you:
value = If(nullable, defaultValueIfNull)
http://visualstudiomagazine.com/listings/list.aspx?id=252
The accepted answer doesn't have any explanation whatsoever and is simply just a link.
Therefore, I thought I'd leave an answer that explains how the If operator works taken from MSDN:
If Operator (Visual Basic)
Uses short-circuit evaluation to conditionally return one of two
values. The If operator can be called with three arguments or with two
arguments.
If( [argument1,] argument2, argument3 )
If Operator Called with Two Arguments
The first argument to If can be omitted. This enables the operator
to be called by using only two arguments. The following list applies
only when the If operator is called with two arguments.
Parts
Term Definition
---- ----------
argument2 Required. Object. Must be a reference or nullable type.
Evaluated and returned when it evaluates to anything
other than Nothing.
argument3 Required. Object.
Evaluated and returned if argument2 evaluates to Nothing.
When the Boolean argument is omitted, the first argument must be a
reference or nullable type. If the first argument evaluates to
Nothing, the value of the second argument is returned. In all other cases, the value of the first argument is returned. The
following example illustrates how this evaluation works.
VB
' Variable first is a nullable type.
Dim first? As Integer = 3
Dim second As Integer = 6
' Variable first <> Nothing, so its value, 3, is returned.
Console.WriteLine(If(first, second))
second = Nothing
' Variable first <> Nothing, so the value of first is returned again.
Console.WriteLine(If(first, second))
first = Nothing
second = 6
' Variable first = Nothing, so 6 is returned.
Console.WriteLine(If(first, second))
An example of how to handle more than two values (nested ifs):
Dim first? As Integer = Nothing
Dim second? As Integer = Nothing
Dim third? As Integer = 6
' The LAST parameter doesn't have to be nullable.
'Alternative: Dim third As Integer = 6
' Writes "6", because the first two values are "Nothing".
Console.WriteLine(If(first, If(second, third)))
You can use an extension method. This one works like SQL COALESCE and is probably overkill for what you are trying to test, but it works.
''' <summary>
''' Returns the first non-null T based on a collection of the root object and the args.
''' </summary>
''' <param name="obj"></param>
''' <param name="args"></param>
''' <returns></returns>
''' <remarks>Usage
''' Dim val as String = "MyVal"
''' Dim result as String = val.Coalesce(String.Empty)
''' *** returns "MyVal"
'''
''' val = Nothing
''' result = val.Coalesce(String.Empty, "MyVal", "YourVal")
''' *** returns String.Empty
'''
''' </remarks>
<System.Runtime.CompilerServices.Extension()> _
Public Function Coalesce(Of T)(ByVal obj As T, ByVal ParamArray args() As T) As T
If obj IsNot Nothing Then
Return obj
End If
Dim arg As T
For Each arg In args
If arg IsNot Nothing Then
Return arg
End If
Next
Return Nothing
End Function
The built-in If(nullable, secondChoice) can only handle two nullable choices. Here, one can Coalesce as many parameters as desired. The first non-null one will be returned, and the rest of the parameters are not evaluated after that (short circuited, like AndAlso/&& and OrElse/|| )
The one significant limitation of most of these solutions is that they won't short-circuit. They are therefore not actually equivalent to ??.
The built-in If operator won't evaluate subsequent parameters unless the earlier parameter evaluates to nothing.
The following statements are equivalent:
C#
var value = expression1 ?? expression2 ?? expression3 ?? expression4;
VB
dim value = if(expression1,if(expression2,if(expression3,expression4)))
This will work in all cases where ?? works. Any of the other solutions would have to be used with extreme caution, as they could easily introduce run-time bugs.
Check Microsoft documentation about If Operator (Visual Basic) here: https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/if-operator
If( [argument1,] argument2, argument3 )
Here are some examples (VB.Net)
' This statement prints TruePart, because the first argument is true.
Console.WriteLine(If(True, "TruePart", "FalsePart"))
' This statement prints FalsePart, because the first argument is false.
Console.WriteLine(If(False, "TruePart", "FalsePart"))
Dim number = 3
' With number set to 3, this statement prints Positive.
Console.WriteLine(If(number >= 0, "Positive", "Negative"))
number = -1
' With number set to -1, this statement prints Negative.
Console.WriteLine(If(number >= 0, "Positive", "Negative"))