Checking for DBNull with generics

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Leon Mayne

    Checking for DBNull with generics

    We currently have lots of checks in our businesslayer object's Load()
    functions that look like:

    If drCourse("txtTT MCnotes").Equal s(DBNull.Value) Then
    Me._txtTTMCnote s = ""
    Else
    Me._txtTTMCnote s = CStr(drCourse(" txtTTMCnotes"))
    End If

    and

    If drCourse("datTT MCarchived").Eq uals(DBNull.Val ue) Then
    Me._datTTMCarch ived = New Nullable(Of DateTime)
    Else
    Me._datTTMCarch ived = CDate(drCourse( "datTTMCarchive d"))
    End If

    I'd like to tidy these up with a a static generic function that will check
    for null, and then return either the value or a default value (e.g. int=0,
    string="", nullables=new nullable) but am having problems with the return
    type. I started with this:

    Public Shared Function CheckDbNull(Of T)(ByVal pReaderVar As Object) As T
    If pReaderVar.Equa ls(DBNull.Value ) Then
    Return Nothing
    Else
    Return CType(pReaderVa r, T)
    End If
    End Function

    Which works, but returns nothing, which is causing null reference
    exceptions. I tried writing it like:

    If pReaderVar.Equa ls(DBNull.Value ) Then
    Select Case GetType(T).Full Name
    Case "System.Str ing"
    Return ""
    Case "System.Int 32"
    Return 0
    ' etc
    End Select

    But this doesn't compile, as the return type is not T. Also trying to use
    e.g. Return CType("", T) doesn't work.

    Does anyone know how to return a specific type based on the return type, or
    do I have to create a separate function for each type I'm checking for?

  • Marc Gravell

    #2
    Re: Checking for DBNull with generics

    Why not obtain the ordinal of the column (GetOrdinal), then use
    IsDBNull to check for null on the column, then finally default(T)* to
    use the default value for that type. The only exception you might want
    here is string (since it looks like you want "") - although personally
    I'd find the null more correct, since you can differentiate between
    the null string and the empty string.

    (*=this is the C# syntax; I'm sure there is a VB equivalent, but I
    don't know what it is ;-p)

    Re casting the string (as an exception) - I don't know enough about
    VB, but in C# you can trick it by doing something like:
    return (T)(object)"";

    Marc

    Comment

    • Marc Gravell

      #3
      Re: Checking for DBNull with generics

      Just for the record, string-compare on GetType is a nasty way to do things -
      surely comparing just the types [i.e. GetType(T) vs GetType(String) etc]
      would be cleaner? Granted: you can't do this in a switch... but If, ElseIf,
      etc should do.

      I'm also a little confused as to what the Nullable<boolet c is doing; it
      *looks* like it is converting an empty Nullable<boolto object (which
      should yield null due to the boxing rules), then converting that null to a
      T, which we already know if Nullable<bool(h ence becoming another empty
      Nullable<bool>)- so we've got a complicated way of saying "null". In C#,
      default(T) here would the same thing... I don't know what VB does, though.

      Marc


      Comment

      • Leon Mayne

        #4
        Re: Checking for DBNull with generics

        "Marc Gravell" <marc.gravell@g mail.comwrote in message
        news:uz5%23tjxk IHA.3888@TK2MSF TNGP03.phx.gbl. ..
        Just for the record, string-compare on GetType is a nasty way to do
        things - surely comparing just the types [i.e. GetType(T) vs
        GetType(String) etc] would be cleaner? Granted: you can't do this in a
        switch... but If, ElseIf, etc should do.
        Yes, that's why I was doing a string compare. Perhaps I should rewrite it as
        you suggest for performance.
        I'm also a little confused as to what the Nullable<boolet c is doing; it
        *looks* like it is converting an empty Nullable<boolto object (which
        should yield null due to the boxing rules), then converting that null to a
        T, which we already know if Nullable<bool(h ence becoming another empty
        Nullable<bool>)- so we've got a complicated way of saying "null". In C#,
        default(T) here would the same thing... I don't know what VB does, though.
        I just checked this and it seems to work fine. It creates a new nullable(of
        boolean) with no value, and HasValue = false. Is this different in C#?
        *Leon checks
        OK, I just tried:

        public static T CheckDBNull<T>( object pReaderVar)
        {
        if (pReaderVar.Equ als(DBNull.Valu e))
        {
        if (typeof(T) == typeof(string))
        {
        return (T)(object)"";
        }
        else if (typeof(T) == typeof(Nullable <bool>))
        {
        return (T)(object)new Nullable<bool>( );
        }
        else
        {
        return default(T);
        }
        }
        else
        {
        return (T)pReaderVar;
        }
        }

        and yes, it returns null for a Nullable<bool>. I wonder why it's different
        for VB.NET? Would be interesting to look at the MSIL.

        Comment

        • Leon Mayne

          #5
          Re: Checking for DBNull with generics


          "Leon Mayne" <leon@rmvme.mvp s.orgwrote in message
          news:C5A348E0-11EE-48E0-B45B-FAB3BDFA0295@mi crosoft.com...
          Would be interesting to look at the MSIL.
          I just did this, and it looks like the VB version is using a different call
          to unbox the object:

          VB:
          IL_00b9: box valuetype [mscorlib]System.Nullable `1<bool>
          IL_00be: call !!0
          [Microsoft.Visua lBasic]Microsoft.Visua lBasic.Compiler Services.Conver sions::ToGeneri cParameter<!!0> (object)

          C#:
          IL_0066: box valuetype [mscorlib]System.Nullable `1<bool>
          IL_006b: unbox.any !!T

          So the Conversions::To GenericParamete r works but the direct unboxing
          doesn't.

          Comment

          • Leon Mayne

            #6
            Re: Checking for DBNull with generics

            "Leon Mayne" <leon@rmvme.mvp s.orgwrote in message
            news:B27662E5-EC82-4A95-B97A-A023D69262E0@mi crosoft.com...
            >
            "Leon Mayne" <leon@rmvme.mvp s.orgwrote in message
            news:C5A348E0-11EE-48E0-B45B-FAB3BDFA0295@mi crosoft.com...
            >Would be interesting to look at the MSIL.
            >
            I just did this, and it looks like the VB version is using a different
            call to unbox the object:
            >
            VB:
            IL_00b9: box valuetype [mscorlib]System.Nullable `1<bool>
            IL_00be: call !!0
            [Microsoft.Visua lBasic]Microsoft.Visua lBasic.Compiler Services.Conver sions::ToGeneri cParameter<!!0> (object)
            >
            C#:
            IL_0066: box valuetype [mscorlib]System.Nullable `1<bool>
            IL_006b: unbox.any !!T
            >
            So the Conversions::To GenericParamete r works but the direct unboxing
            doesn't.
            Just tried it myself:

            Return
            Microsoft.Visua lBasic.Compiler Services.Conver sions.ToGeneric Parameter(Of
            T)(New Nullable(Of Boolean))

            Works fine in VB.NET, but not in C#:

            return
            Microsoft.Visua lBasic.Compiler Services.Conver sions.ToGeneric Parameter<T>(ne w
            Nullable<Boolea n>());

            Something odd going on here!

            Comment

            Working...