I eventually implemented Neolisk's suggestion, which had the advantage of being short, all-encompassing and very re-usable:
Public Function IsDefaultObject(obj As Object) As Boolean
Return obj.Equals(GetDefaultValue(obj.GetType()))
End Function
Public Function GetDefaultValue(t As Type) As Object
If (t.IsValueType) Then Return Activator.CreateInstance(t)
Return Nothing
End Function
I originally went with the solution of creating a function IsDefaultObject(obj) which tells me if an object has had a default value assigned. I planned to add to it as more types got noticed.
Private Function IsDefaultObject(obj As Object) As Boolean
If obj Is Nothing Then Return True
If String.IsNullOrEmpty(obj.ToString()) Then Return True
If obj.Equals(0) Then Return True
If obj.Equals(New Date()) Then Return True
Return False
End Function
Of course, I could have used the solution in Hans Passant's comment:
Private Function IsDefaultObject(obj As Object) As Boolean
Return Microsoft.VisualBasic.CompilerServices.Operators.
ConditionalCompareObjectEqual(obj, Nothing, False)
End Function