Nullable object must have a value in IComparable.CompareTo - asp.net

I have a custom class that needs to be sortable using a Nullable(of Double) property. I have defined the class, and implemented iCompare. Within my code, I thought I had placed sufficient checks for Null values, but I am suddenly seeing this error...
Nullable object must have a value.
...on this line:
Return Me.SomeDouble.Value.CompareTo(CType(obj, MatrixCellData).SomeDouble.Value)
Can anyone please explain why this is happening? I know that usually this error can be easily avoided by using Double.HasValue, which I have included. The full sample code to reproduce is below.
Namespace MyApp
Public Class MatrixCellData
Implements IComparable
Public Property SomeDouble As Nullable(Of Double)
Public Function CompareTo(obj As Object) As Integer Implements System.IComparable.CompareTo
If obj Is Nothing OrElse IsDBNull(obj) OrElse Not TypeOf (obj) Is MatrixCellData Then
Return 1
Else
If Not Me.SomeDouble.HasValue Then
Return -1
Else
Return Me.SomeDouble.Value.CompareTo(CType(obj, MatrixCellData).SomeDouble.Value)
End If
End If
End Function
End Class
End Namespace
Breaking code...
Dim lst As New List(Of MyApp.MatrixCellData)
lst.Add(New MyApp.MatrixCellData With {.SomeDouble = 75})
lst.Add(New MyApp.MatrixCellData With {.SomeDouble = 25})
lst.Add(New MyApp.MatrixCellData With {.SomeDouble = Nothing})
lst.Sort() ' Triggers error

If you don't use
If Not Me.SomeDouble.HasValue Then
Then there's no check to stop Me.SomeDouble from being equal to Nothing.
When you call the sort function on your list, you will be calling the CompareTo function at least once for each item. Effectively, the framework tries to place your last item somewhere in the ordered list the call looks similar to this:
(New MatrixCellData With {.SomeDouble = Nothing}).CompareTo(New MatrixCellData With {.SomeDouble = 25})
All the following checks are false:
If obj Is Nothing OrElse IsDBNull(obj) OrElse Not TypeOf (obj) Is MatrixCellData Then
Obj isn't Nothing, (Me.SomeDouble is Nothing)
This means your last line in the CompareTo method
Return Me.SomeDouble.Value.CompareTo(CType(obj, MatrixCellData).SomeDouble.Value)
In the case where Me.SomeDouble is Nothing, will actually be:
Return Nothing.Value.CompareTo(CType(obj, MatrixCellData).SomeDouble.Value)
Which of course doesn't make sense since Nothing does not have a 'Value' method or property.
I would re-write this as
Public Function CompareTo(obj As Object) As Integer Implements System.IComparable.CompareTo
If obj Is Nothing OrElse Not TypeOf (obj) Is MatrixCellData OrElse CType(obj, MatrixCellData).SomeDouble Is Nothing Then
Return 1
Else If Me.SomeDouble is Nothing Then
Return -1
End If
Return Me.SomeDouble.Value.CompareTo(CType(obj, MatrixCellData).SomeDouble.Value)
End Function

Related

VB.Net Check to see if Type is an IEnumerable

I have System.Type object (retType). I get this with Reflection from my policy object that I pass in . How can I test to see if its enumerable? Any help would be most appreciated code is below.
Public Shared Function SerializeChanges(p As Model.Policy_2.Policy) As XmlDocument
Dim polProps As PropertyInfo() = p.GetType().GetProperties()
For Each pi As PropertyInfo In polProps
Dim retType As Type = pi.PropertyType
' This line belowthrows an error that IEnumerable is an Interface and cannot be used as an expression
If retType Is IEnumerable Then
'Do Stuff
End If
End Function
The following method is a generic method to check whether a given type inherits or implements another type:
Function InheritsOrImplements(child As Type, parent As Type) As Boolean
If child Is Nothing OrElse parent Is Nothing Then
Return False
End If
parent = resolveGenericTypeDefinition(parent)
If parent.IsAssignableFrom(child) Then
Return True
End If
Dim currentChild = If(child.IsGenericType, child.GetGenericTypeDefinition(), child)
While currentChild <> GetType(Object)
If parent = currentChild OrElse hasAnyInterfaces(parent, currentChild) Then
Return True
End If
currentChild = If(currentChild.BaseType IsNot Nothing AndAlso currentChild.BaseType.IsGenericType, currentChild.BaseType.GetGenericTypeDefinition(), currentChild.BaseType)
If currentChild Is Nothing Then
Return False
End If
End While
Return False
End Function
Function hasAnyInterfaces(parent As Type, child As Type) As Boolean
Return child.GetInterfaces().Any(Function(childInterface)
Dim currentInterface = If(childInterface.IsGenericType, childInterface.GetGenericTypeDefinition(), childInterface)
Return currentInterface = parent
End Function)
End Function
Function resolveGenericTypeDefinition(type As Type) As Type
Dim shouldUseGenericType = Not (type.IsGenericType AndAlso type.GetGenericTypeDefinition() <> type)
If type.IsGenericType AndAlso shouldUseGenericType Then
type = type.GetGenericTypeDefinition()
End If
Return type
End Function
Taken from https://github.com/shaynevanasperen/Quarks/blob/master/Quarks/TypeExtensions/InheritsOrImplements.cs
Usage:
InheritsOrImplements(retType, GetType(IEnumerable))

Routine to compare new and old string values, maintain old data if nothing new

I have a Form which allows users to enter new Data for a record. In order to maintain Data Integrity, I copy all the pre-existing Data (if Any) into the Record and overwrite only those fields which the user has added new Data to. This new Record is saved to the database and the old Record Deleted.
I'm merely trying to find the most efficient way of going through each field to :
determine if there is Current Data to Maintain
New Data to Overwrite
I'll need to write the same type of Check for String, Decimal, Date and Integer (all nullable)
Here's my string check
Private Function CreateRecordforSubmission() As Business.Casualty
Dim c As Business.Casualty = Casualty
c.alias = CheckStringValues(c.alias, txtAlias.Text.Trim())
Return c
End Function
Private Function CheckStringValues(OldValue As String, newValue As String) As String
If Not OldValue Is Nothing AndAlso Not String.IsNullOrEmpty(newValue) Then
'<-- There is NEW DATA
If Not String.IsNullOrEmpty(newValue) Then
Return newValue
Else
'<-- No NEW DATA, check of there is CURRENT DATA to maintain
If Not OldValue Is Nothing Then
Return OldValue
Else
Return String.Empty
End If
End If
Else
'<-- NO CURRENT DATA AND no changes have been made
Return String.Empty
End If
End Function
Check out how CSLA does it. Each property in your object could take care of that comparison, if the setter detect a change or new value, you can update your variable and mark your object as modified.
Public Property Alias As String
Get
Return _alias
End Get
Set(ByVal value As String)
If Not String.IsNullOrEmpty(value) AndAlso _alias <> value Then
_alias = value
_objectWasModified = True
End If
End Set
End Property
The If statement could be in the base class, or a helper class.
If you want to have a generic function for other type, here's an example. This assume that you are using nullable values.
Public Property Number As Integer?
Get
Return _number
End Get
Set(ByVal value As Integer?)
If Not IsNullOrSame(Of Integer)(_number, value)Then
_number= value
_objectWasModified = True
End If
End Set
End Property
Public Function IsNullOrSame(Of T As Structure)(ByVal oldValue As Nullable(Of T), ByVal newValue As Nullable(Of T))
If newValue.HasValue Then
If Not oldValue.HasValue OrElse Not oldValue.Value.Equals(newValue.Value) Then
Return False
End If
End If
Return True
End Function

Understanding how Public Properties are set in VB.NET

I am trying to understand how a value in a Public property is set. There does not seem to be anything passed or any kind of lookup.
Public Shared Property IsUser() As String
Get
If HttpContext.Current.Session("IsUser") IsNot Nothing Then
Return HttpContext.Current.Session("IsUser").ToString()
Else
Return Nothing
End If
End Get
Set(value As String)
HttpContext.Current.Session("IsUser") = value
End Set
End Property
I have tried searching for the ClassName i.e. UserSession.IsUser = and also the only place the session value is set is in the property. HttpContext.Current.Session("IsUser") = value
What do I need to understand better.. I mean at the end of the day the User has to be True or False so where is the Lookup or passed parameter?

Property getting incorrect value set

I have a bizarre problem. I use a lot of session variables so I don't have to pass it all back and forth every time a page does a postback. I have been doing this for years so I'm at a complete loss.
I have a file called SessionHandler.vb in the App_Code folder that has the following code:
Imports Microsoft.VisualBasic
Public Class SessionHandler
Private Shared _chgLinePkNum As String = "0"
Private Shared _chgStudentIDPk As String = "0"
Public Shared Property chgLinePkNum() As String
Get
' Check for null first
If (HttpContext.Current.Session(SessionHandler._chgLinePkNum) Is Nothing) Then
' Return an empty string if session variable is null.
Return "Nothing"
Else
Return HttpContext.Current.Session(SessionHandler._chgLinePkNum).ToString()
End If
End Get
Set(ByVal value As String)
If (value Is Nothing) Or (value = "") Then
HttpContext.Current.Session(SessionHandler._chgLinePkNum) = "Nothing"
Else
HttpContext.Current.Session(SessionHandler._chgLinePkNum) = value
End If
End Set
End Property
Public Shared Property chgStudentIDPk() As String
Get
' Check for null first
If (HttpContext.Current.Session(SessionHandler._chgStudentIDPk) Is Nothing) Then
' Return an empty string if session variable is null.
Return "Nothing"
Else
Return HttpContext.Current.Session(SessionHandler._chgStudentIDPk).ToString()
End If
End Get
Set(ByVal value As String)
If (value Is Nothing) Or (value = "") Then
HttpContext.Current.Session(SessionHandler._chgStudentIDPk) = "Nothing"
Else
HttpContext.Current.Session(SessionHandler._chgStudentIDPk) = value
End If
End Set
End Property
Simple enough... Then, in my code, I reference the properties by SessionHandler.chgLinePkNum. This block of code has LineItemNumber = 1 and StudentID = [the actual ID number].
If IsParking And checkbox.Checked = True Then
SessionHandler.chgLinePkNum = LineItemNumber
SessionHandler.chgStudentIDPk = StudentID
peParkingRegistration.Show()
End If
When the first line runs, chgLinePkNum is set to 1 as expected. For some strange reason, it is also setting chgStudentIDPk to 1. When the next line is run, it sets chgStudentIDPk to the correct StudentID number. The problem is, it also sets chgLinePkNum to the StudentID number.
I have run it line by line in the debugger and each property set function runs only when it is called. I just can't figure out how "HttpContext.Current.Session(SessionHandler._chgLinePkNum) = value" is setting the value for chgStudentIDPk and vice versa.
Anything to do with these having the exact same value?
Private Shared _chgLinePkNum As String = "0"
Private Shared _chgStudentIDPk As String = "0"

Properly Defining a Singleton in asp.net

I've the following class which is a singleton implementation:
Imports Microsoft.VisualBasic
Imports System.Xml
Public Class GlobalController
Private Shared instance As GlobalController
Private ControlsXmlDoc As XmlDocument
Private xmldocpath As String
Sub New()
ControlsXmlDoc = New XmlDocument
xmldocpath = HttpContext.Current.Server.MapPath("~/cp/GlobalControl.xml")
ControlsXmlDoc.Load(xmldocpath)
End Sub
Shared Function GetInstance() As GlobalController
If instance Is Nothing Then
Return New GlobalController
Else
Return instance
End If
End Function
Shared Property IsExtracting() As Boolean
Get
Return Boolean.Parse(GetInstance.ControlsXmlDoc.SelectNodes("global/extraction/proceed").Item(0).InnerText)
End Get
Set(ByVal value As Boolean)
HttpContext.Current.Application.Lock()
Dim node As XmlNode = GetInstance.ControlsXmlDoc.SelectNodes("global/extraction/proceed").Item(0)
If Not Boolean.Parse(node.InnerText) = value Then
node.InnerText = value.ToString
node.Normalize()
SaveDocument()
GetInstance.ControlsXmlDoc.Load(GetInstance.xmldocpath)
End If
HttpContext.Current.Application.UnLock()
End Set
End Property
Shared Sub SaveDocument()
GetInstance.ControlsXmlDoc.Save(GetInstance.xmldocpath)
End Sub
End Class
In my page I am doing something like this:
GlobalController.IsExtracting = False
Response.Write(GlobalController.IsExtracting)
I am always getting the output as "true". What is wrong with the code?
According this link Operator precedence and associativity, ! (or vb.net Not) have greater priority than == (= in VB.NET); so, your expression is always evaluated as
Not(True) And False
and never enters that If statement.
Try to use Boolean.Parse(node.InnerText) != value or Not (Boolean.Parse(node.InnerText) = value) in order to get correct result.
All, thanx for ur answers. I apologize for what I am about to say. I found the bug: it was with the way I implemented the singleton. Forgot to assign the newly created object instance to the shared variable.
Shared Function GetInstance() As GlobalController
If instance Is Nothing Then
instance = New GlobalController
End If
Return instance
End Function

Resources