Set date variable to null - sql

Dim dtIzvrsenja datetime
Private Sub chkDate_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkDate.CheckedChanged
If Me.chkDate.Checked Then
Me.dtpDate.CustomFormat = "dd.MM.yyyy"
Me.dtpDate.Enabled = True
dtIzvrsenja = dtpdate.value
Else
Me.dtpDate.CustomFormat = " "
Me.dtpDate.Enabled = False
dtIzvrsenja = Nothing
End If
End Sub
Is there any way to set the value of dtIzvrsenja to null if chk is not checked ?
Edit by using the way other mentioned.
{"Nullable object must have a value."}
Dim dtIzvrsenja2 As DateTime? = Nothing
dtIzvrsenja = dtIzvrsenja2

In order to support that, you need to use the generic Nullable(Of Date) type rather than just Date (the VB alias for the DateTime type). Normally, only reference type variables (Class type variables) support null values. Since Date is a value type variable (Structure), it doesn't support null. Nullable(Of T) allows you to wrap any value type and add support for null values to that type.
In VB (as well as C#, by the way), a question mark after any type name is shorthand for making the type nullable. So, Date? is equivalent to Nullable(Of Date). Here's your example code using nullables:
Dim dtIzvrsenja As Date?
Private Sub chkDate_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkDate.CheckedChanged
If Me.chkDate.Checked Then
Me.dtpDate.CustomFormat = "dd.MM.yyyy"
Me.dtpDate.Enabled = True
dtIzvrsenja = dtpdate.value
Else
Me.dtpDate.CustomFormat = " "
Me.dtpDate.Enabled = False
dtIzvrsenja = Nothing
End If
End Sub
However, the confusing thing about Nullable(Of T) is that it, itself, is not a reference type. Nullable(Of T) is a value type. So, even Nullable(Of Date) variables cannot be set to null in the traditional sense. What Nullable(Of T) does is it adds a HasValue As Boolean property which allows you to check if the value is null. Therefore, when you go to read the value of the variable, rather than first checking to see if the variable Is Nothing, you need to instead check to see if it's HasValue property is true. For instance:
If dtIzvrsenja.HasValue Then
Dim dtIzvrsenja2 As Date = dtIzvrsenja.Value
' ...
End If
If you really want to treat the Date type as a real reference type, then you can do so by declaring the variable As Object. Object variables are always reference variables, so when set to Nothing, they really are set to null. When you set an Object variable to a value-type value, such as a Date, it will box the value. When you read it's value and convert it back to a Date, it will go through a process called unboxing. This boxing/unboxing process does add some overhead, however. Also, the other downside of this is that the type-checking for code working with the Object variable will be skipped at compile-time. That means that, if you are not careful, you could get some exceptions at runtime if the variable references a type of object that is different than what you expect. You could avoid the type-checking issue by declaring your own class:
Public Class DateReference
Public Property Value As Date
End Class
Or:
Public Class Reference(Of T)
Public Property Value As T
End Class
However, that seems silly. Nullable(Of T) already serves that purpose, so unless you really need to make it a reference type, I'd suggest that you take the time to get acquainted with the standard way of doing it.
As a side note, another complication which further causes confusion in this area is that VB's Nothing keyword does not strictly mean null. It just means the deafult value for any type. So, for an Integer, Nothing equals the value zero. For a Date, it means Date.MinValue, etc.

Use Nullable:
Dim nullableDateValue As New Nullable(Of Date) = Nothing

You can also use the question mark (Nullable) specifier, though this is probably outmoded now...
Dim dtIzvrsenja As DateTime? = Nothing

Related

VB.NET Nothing evaluating to False [duplicate]

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

Reference and Value types

I have read that String was a "reference type", unlike integers. MS website
I tried to test its behavior.
Sub Main()
Dim s As New TheTest
s.TheString = "42"
Dim z As String = s.GimmeTheString
z = z & "000"
Dim E As String = s.TheString
s.GimmeByref(z)
end sub
Class TheTest
Public TheString As String
Public Function GimmeTheString() As String
Return TheString
End Function
Public Sub GimmeByref(s As String)
s = TheString
End Sub
End Class
So I expected :
z is same reference as TheString, thus TheString would be set to "42000"
Then Z is modified by reference by GimmeByref thus Z is set to whatever TheString is
Actual result:
Z="42000"
E="42"
TheString="42"
What point am I missing?
I also tried adding "ByRef" in GimmeByRef : yes obviously the GimmeByRef does work as expected, but it also does if I put everything as Integer, which are said to be "Value type".
Is there any actual difference between those types?
The confusion comes about because regardless of type, argument passing in VB is pass by value by default.
If you want to pass an argument by reference, you need to specify the argument type as ByRef:
Public Sub GimmeByref(ByRef s As String)
You also need to understand the difference between mutating a value and re-assigning a variable. Doing s = TheString inside the method doesn’t mutate the value of the string, it reassigns s. This can obviously be done regardless of whether a type is a value or reference type.
The difference between value and reference types comes to bear when modifying the value itself, not a variable:
obj.ModifyMe()
Strings in .NET are immutable and thus don’t possess any such methods (same as integers). However, List(Of String), for instance, is a mutable reference type. So if you modify an argument of type List(Of String), even if it is passed by value, then the object itself is modified beyond the scope of the method.
Strings are immutable, every time you do a change it creates a new "reference" like if New was called.
A String object is called immutable (read-only), because its value
cannot be modified after it has been created. Methods that appear to
modify a String object actually return a new String object that
contains the modification. Ref
Your code basically does something like this:
Sub Main()
Dim a, b As String
a = "12"
b = a
a = a & "13"
Console.WriteLine(a) ' 1213
Console.WriteLine(b) ' 12
Console.ReadLine()
End Sub

How to assign a value to a variable of type Double, that has been passed as Object?

I am trying to assign a value to global variable, which has a Property of type Double. This Property is passed as Object and the assignment fails.
In the example code below, the value is never assigned to the actual object, but only locally:
Public Class Form1
Friend Home As New Building
Private Sub AssignValues() Handles Me.Load
'Objects of different types are added to a list
Dim listObjects As New List(Of Object)
listObjects.Add(Home.Surface)
'All the Objects in listObjects are assigned a value that
'is stored as String
For Each o As Object In listObjects
SetProperty(o, "45.6")
Debug.Print("Surface = " & Home.Surface.ToString)
Next
End Sub
Private Sub SetProperty(ByRef Variable As Object, ByVal Value As String)
Select Case Variable.GetType
Case GetType(Double)
Variable = CDbl(Value)
Case Else
'...
End Select
End Sub
End Class
Public Class Building
Dim _surface As Double = 0
Public Property Surface As Double
Get
Return _surface
End Get
Set(ByVal value As Double)
_surface = value
End Set
End Property
End Class
The program invariably outputs Surface = 0 instead of 45.6. What am I doing wrong?
I tried to pass the Variable as reference, as suggested here, but without success. I also read about using Reflection, but there ought to be something simpler than that...
When your adding home.surface to the list, your adding a copy of the double to the list and then adjusting that copy. Stick a watch on "o" and see how it changes whilst home.surface remains the same.
If you want to use reflection, try something along these lines.
Dim prop As Reflection.PropertyInfo = o.GetType().GetProperty("Surface")
prop.SetValue(o, 45.6)
With Variable.GetType you will get always Object, because this is the type of Variable. What you can do with an Object is converting/casting it into a different type (like Double).
The best way to determine the "original type" from where the Object comes would be including an additional variable telling it. Another option might be converting the given Object into the target Type and see if it is not nothing/does not trigger an error. But this second option is not too accurate, mainly when dealing with "equivalent types" like Doubles/Integers.

vb.net Loop through public structure and pass to generics

I have inherited some god awful vb.net code and having trouble trying to work out the generics for looping through the current structure in place.
here is a snippet of the struct
Public Structure ApplicationDetails
Dim ID As Integer
Dim AgentID As Integer
Dim ApplicationDate As Date
Dim CompletedDate As Date
here is the madness to populate it
With ApplicationInfo
.ID = If(Not IsDBNull(DT(0)("ID")), DT(0)("ID"), Nothing)
.ApplicationDate = If(Not IsDBNull(DT(0)("ApplicationDate")), DT(0)("MortgageAmount"), Nothing)
.CompletedDate = If(Not IsDBNull(DT(0)("CompleteDate")), DT(0)("MortgageAmount"), Nothing)
now i want to do something like this:
For Each item In ApplicationInfo.GetType().GetProperties()
Dim thisType = item.GetType()
Dim name = item.Name
Dim value = DtItem(Of item.GetType())(0, name.ToString(), DT)
item.SetValue(item, value, Nothing)
Next
Private Function DtItem(Of T)(ByVal num As Integer, ByVal name As String, ByRef DT As DataTable) As T
Return If(Not IsDBNull(DT(num)(name)), DT(num)(name), Nothing)
End Function
but i am not sure on the syntax to set the value and when trying to get the type i get item.GetTYpe() is not declared. I know i must be on the right track, just missing a little something.
A number of issues.
First and foremost, SetValue only works on object types, not values, so you would have to change your Structure to a Class.
Public Class ApplicationDetails
End Class
Next, you are looping through properties but your "structure" only had fields. So you need to add properties:
Public Class ApplicationDetails
Private _ID As Integer
Property ID As Integer
Get
Return _ID
End Get
Set(ByVal value As Integer)
_ID = value
End Set
End Property
//' etc
End Class
Otherwise, you would have to work with GetFields.
I don't think Generics will work here since you are only dealing with objects and you don't know the type (despite reflection):
Private Function DtItem(ByVal num As Integer, ByVal name As String, ByRef DT As DataTable) As Object
Return If(Not IsDBNull(DT(num)(name)), DT(num)(name), Nothing)
End Function
Lastly, your reflection call is wrong. Try changing it to this:
For Each item As PropertyInfo In ApplicationInfo.GetType().GetProperties
Dim value As Object = DtItem(0, item.Name, _dt)
If item.CanWrite Then
item.SetValue(ApplicationInfo, value, Nothing)
End If
Next
I'm not sure doing this through reflection is gaining you anything. In your "madness" example, it looks like you might be trying to put in a MortgageAmount, which I assume is a decimal, into a date field. That might be needed to look at.
I think you need to rethink your functional decomposition there. You're not getting much out of moving one line into a function, and I don't think you'll be able to pass a type constructor to a generic the way you are attempting to do so. You're also confusing some of your type checks.
Try something along these lines instead:
For Each item In ApplicationInfo.GetType().GetProperties()
Dim theName As String = item.Name,
isNullable = Not item.PropertyType.IsValueType OrElse _
Nullable.GetUnderlyingType(item.PropertyType) IsNot Nothing
If item.CanWrite Then
If Not IsDBNull(DT(0)(theName))
item.SetValue(ApplicationInfo, DT(0)(theName), Nothing)
ElseIf isNullable
item.SetValue(ApplicationInfo, Nothing, Nothing)
End If
End If
Next
If your code is executed immediately after the object is initialized, the isNullable checks are extraneous and you could simply take no action as the properties will be initialized as null. Otherwise, I'd recommend performing the check so you don't attempt to assign Nothing to a value type, which is going to throw an exception. Alternatively, you could modify your structure to use nullable reference types, i.e.:
Public Structure ApplicationDetails
Property ID As Integer?
Property AgentID As Integer?
Property ApplicationDate As Date?
Property CompletedDate As Date?
End Structure
EDIT
As LarsTech points out, your structure members are not properties and this will not function as anticipated unless you modify your structure to indicate these fields are in fact properties, for which the compiler would automatically generate getters and setters.

Why can't I check if a 'DateTime' is 'Nothing'?

In VB.NET, is there a way to set a DateTime variable to "not set"? And why is it possible to set a DateTime to Nothing, but not possible to check if it is Nothing? For example:
Dim d As DateTime = Nothing
Dim boolNotSet As Boolean = d Is Nothing
The second statement throws this error:
'Is' operator does not accept operands of type 'Date'. Operands must be reference or
nullable types.
This is one of the biggest sources of confusion with VB.Net, IMO.
Nothing in VB.Net is the equivalent of default(T) in C#: the default value for the given type.
For value types, this is essentially the equivalent of 'zero': 0 for Integer, False for Boolean, DateTime.MinValue for DateTime, ...
For reference types, it is the null value (a reference that refers to, well, nothing).
The statement d Is Nothing is therefore equivalent to d Is DateTime.MinValue, which obviously does not compile.
Solutions: as others have said
Either use DateTime? (i.e. Nullable(Of DateTime)). This is my preferred solution.
Or use d = DateTime.MinValue or equivalently d = Nothing
In the context of the original code, you could use:
Dim d As DateTime? = Nothing
Dim boolNotSet As Boolean = Not d.HasValue
A more comprehensive explanation can be found on Anthony D. Green's blog
DateTime is a value type, which is why it can't be null. You can check for it to be equal to DateTime.MinValue, or you can use Nullable(Of DateTime) instead.
VB sometimes "helpfully" makes you think it's doing something it's not. When it lets you set a Date to Nothing, it's really setting it to some other value, maybe MinValue.
See this question for an extensive discussion of value types vs. reference types.
DateTime is a value type, which means it always has some value.
It's like an integer - it can be 0, or 1, or less than zero, but it can never be "nothing".
If you want a DateTime that can take the value Nothing, use a Nullable DateTime.
Some examples on working with nullable DateTime values.
(See Nullable Value Types (Visual Basic) for more.)
'
' An ordinary DateTime declaration. It is *not* nullable. Setting it to
' 'Nothing' actually results in a non-null value.
'
Dim d1 As DateTime = Nothing
Console.WriteLine(String.Format("d1 = [{0}]\n", d1))
' Output: d1 = [1/1/0001 12:00:00 AM]
' Console.WriteLine(String.Format("d1 is Nothing? [{0}]\n", (d1 Is Nothing)))
'
' Compilation error on above expression '(d1 Is Nothing)':
'
' 'Is' operator does not accept operands of type 'Date'.
' Operands must be reference or nullable types.
'
' Three different but equivalent ways to declare a DateTime
' nullable:
'
Dim d2? As DateTime = Nothing
Console.WriteLine(String.Format("d2 = [{0}][{1}]\n", d2, (d2 Is Nothing)))
' Output: d2 = [][True]
Dim d3 As DateTime? = Nothing
Console.WriteLine(String.Format("d3 = [{0}][{1}]\n", d3, (d3 Is Nothing)))
' Output: d3 = [][True]
Dim d4 As Nullable(Of DateTime) = Nothing
Console.WriteLine(String.Format("d4 = [{0}][{1}]\n", d4, (d4 Is Nothing)))
' Output: d4 = [][True]
Also, on how to check whether a variable is null (from Nothing (Visual Basic)):
When checking whether a reference (or nullable value type) variable is null, do not use = Nothing or <> Nothing. Always use Is Nothing or IsNot Nothing.
In any programming language, be careful when using Nulls. The example above shows another issue. If you use a type of Nullable, that means that the variables instantiated from that type can hold the value System.DBNull.Value; not that it has changed the interpretation of setting the value to default using "= Nothing" or that the Object of the value can now support a null reference. Just a warning... happy coding!
You could create a separate class containing a value type. An object created from such a class would be a reference type, which could be assigned Nothing. An example:
Public Class DateTimeNullable
Private _value As DateTime
'properties
Public Property Value() As DateTime
Get
Return _value
End Get
Set(ByVal value As DateTime)
_value = value
End Set
End Property
'constructors
Public Sub New()
Value = DateTime.MinValue
End Sub
Public Sub New(ByVal dt As DateTime)
Value = dt
End Sub
'overridables
Public Overrides Function ToString() As String
Return Value.ToString()
End Function
End Class
'in Main():
Dim dtn As DateTimeNullable = Nothing
Dim strTest1 As String = "Falied"
Dim strTest2 As String = "Failed"
If dtn Is Nothing Then strTest1 = "Succeeded"
dtn = New DateTimeNullable(DateTime.Now)
If dtn Is Nothing Then strTest2 = "Succeeded"
Console.WriteLine("test1: " & strTest1)
Console.WriteLine("test2: " & strTest2)
Console.WriteLine(".ToString() = " & dtn.ToString())
Console.WriteLine(".Value.ToString() = " & dtn.Value.ToString())
Console.ReadKey()
' Output:
'test1: Succeeded()
'test2: Failed()
'.ToString() = 4/10/2012 11:28:10 AM
'.Value.ToString() = 4/10/2012 11:28:10 AM
Then you could pick and choose overridables to make it do what you need. Lot of work - but if you really need it, you can do it.
You can also use below just simple to check:
If startDate <> Nothing Then
your logic
End If
It will check that the startDate variable of DateTime datatype is null or not.
You can check this like below :
if varDate = "#01/01/0001#" then
' blank date. do something.
else
' Date is not blank. Do some other thing
end if
A way around this would be to use Object datatype instead:
Private _myDate As Object
Private Property MyDate As Date
Get
If IsNothing(_myDate) Then Return Nothing
Return CDate(_myDate)
End Get
Set(value As Date)
If date = Nothing Then
_myDate = Nothing
Return
End If
_myDate = value
End Set
End Property
Then you can set the date to nothing like so:
MyDate = Nothing
Dim theDate As Date = MyDate
If theDate = Nothing Then
'date is nothing
End If