4

In a legacy application, we have a SqlDataReader. The following field creates a InvalidCastException with a bit field.

public static T GetValueOrNull<T>(this IDataReader reader, string column)
{
     int ordinal;
     if(!string.IsNullOrEmpty(column) && !reader.IsDBNull(reader.GetOrdinal(column)))
          if(int.TryParse(reader.GetOrdinal(column).ToString(), out ordinal))
               return (T)reader.GetValue(ordinal);

      return default(T);
}

What is odd, is that (T)reader.GetValue(ordinal) does assign a valid type. It assigns a false, but the error still occurs. I'm not entirely sure why.

If I perform GetType(); it does indeed show Boolean type. I've also checked to ensure that it is threadsafe.

Greg
  • 11,302
  • 2
  • 48
  • 79
  • How do you know it returns false? – Alexandre Pepin Apr 14 '15 at 16:42
  • @AlexandrePepin Instead of `return` I assigned to a variable, which did show it as a `false`. – Greg Apr 14 '15 at 16:43
  • 1
    Just to verify, `reader.GetValue(ordinal) == typeof(bool)`? – Chris Apr 14 '15 at 16:43
  • @Chris `reader.GetValue(ordinal)` by default will return `object`. Since it is retrieving from Sql. That is why I cast to the desired type for my model. – Greg Apr 14 '15 at 16:43
  • Which statement throws the `InvalidCastException`? – haim770 Apr 14 '15 at 16:45
  • @haim770 `return (T)reader.GetValue(ordinal)` is the line that will throw. – Greg Apr 14 '15 at 16:46
  • If it throws how is it evaluated to `false`? – haim770 Apr 14 '15 at 16:47
  • @Greg That's just the return type of the method, the value should still be a (boxed) `bool`, which is an `object`. If `GetType()` returns `typeof(bool)` the cast will work. – Chris Apr 14 '15 at 16:47
  • Well what is the actual type of reader.GetValue(ordinal)? You should be able to see this during debugging. – Jeroen Vannevel Apr 14 '15 at 16:48
  • What does reader.GetValue(ordinal); give you as a type? – IdahoSixString Apr 14 '15 at 16:48
  • @haim770 I pushed the line down and actually pushed directly to a variable. Which showed the value. – Greg Apr 14 '15 at 16:48
  • @Greg ok while you have gotten the value pushed directly to a variable, what is the type? – IdahoSixString Apr 14 '15 at 16:49
  • 3
    As a side note, what's the point of doing a `ToString` and then parsing the ordinal? – Chris Apr 14 '15 at 16:53
  • @Chris `GetOrdinal` should return an `int`, however to avoid a potential exception I used a `TryParse` which requires a type of `string`. – Greg Apr 14 '15 at 17:01
  • Have you have checked that `T` is `bool`? Are you absolutely sure the exception occurs at this point and that your project has compiled correctly? Also, if `(T)reader.GetValue(ordinal)` works when you assign it to a variable, what happens if you return that variable? – sgmoore Apr 14 '15 at 17:04
  • 1
    @Greg `GetOrdinal` will either give you a valid ordinal integer, or throw. I don't see what possible exception you can avoid doing all that... – Chris Apr 14 '15 at 17:12
  • Do `Type t1 = typeof(T), t2 = reader.GetValue(ordinal).GetType();` before the first return, set a breakpoint and show us what you get. – Chris Apr 14 '15 at 17:19
  • I suspect OP needs to cast to bool? because his bit field is nullable, or he is using tinyint and needs to cast to byte. – moarboilerplate Apr 14 '15 at 17:21
  • 2
    @Greg call `reader.GetFieldType(ordinal)` to see what type you need to cast to. I'm fairly certain you'll see `Nullable`, `byte`, or `Nullable` returned. – moarboilerplate Apr 14 '15 at 18:21

1 Answers1

1

The reason the code would fail on a the bit field, which would be correlated to a boolean was due to the inferred type. The underlying data type wasn't bool but rather a bool?.

Once the model reflected a nullable boolean, the code worked as intended.

Greg
  • 11,302
  • 2
  • 48
  • 79