Recently, I ran into a problem where I needed to cast from an unknown type to a known type.  Normally this would be fine as I a generic cast.  For example...

    1 public static T ValueOf<T>( this OracleCommand command, string parameterName )

    2 {

    3     return (T)command.Parameters[parameterName].Value;

    4 }


The parameter of course returns an object and I wanted to streamline the parameter value lookup process.  All was well until I started using ODP.Net (instead of Microsofts OracleClient).  With the OracleClient, the underlying type would be a standard system type.  So myCommand.ValueOf<DateTime>("myDateParam") would work fine.  However, ODP would return proprietary oracle types like OracleDate and myCommand.ValueOf<DateTime>("myDateParam") would fail at runtime.

This puzzled me at first (still does really), because there are explicit cast operators between OracleDate and DateTime.  The problem lies in the fact that we are still dealing with Object, not the specific type. 

While debugging I notice something interesting.  Though the system could tell the underlying type was OracleDate it still referenced it as Object.  So (DateTime)myObject would fail at runtime, but (DateTime)(OracleDate)myObject would not.

I was very close to abandoning my ValueOf extension as it didn't really do much anyway.  But I did some searching on other ways to cast dynamically.  I found this post that gave me a kick start.

    1 public static T CastTo<T>( this object input )

    2 {

    3     Type outputType = typeof( T );

    4 

    5     if(outputType.IsInstanceOfType( input ))

    6         return (T)input;

    7 

    8     Type inputType = input.GetType();

    9     MethodInfo method = inputType

   10                             .GetMethods( BindingFlags.Static | BindingFlags.Public )

   11                             .FirstOrDefault(

   12                                 m =>

   13                                     m.Name.In( "op_Implicit", "op_Explicit" ) &&

   14                                     m.ReturnType == outputType );

   15 

   16     if(method == null)

   17         throw new InvalidCastException( string.Format( "Cannot cast from {0} to {1}", inputType.Name, outputType.Name ) );

   18 

   19     return (T)method.Invoke( null, new object[] { input } );

   20 }


By the way, line 13 contains "In", an extension method I blogged about a while back.

I am not sure that using reflection will pay off in the end, but I don't expect it to be a problem for now.  None of the places where I am using it involve bulk operatons.  My updated ValueOf looks like this:

    1 public static T ValueOf<T>( this OracleCommand command, string parameterName )

    2 {

    3     return command.Parameters[parameterName].Value.CastTo<T>();

    4 }

Still, I find it strange that the runtime generic cast isn't smart enough to handle this on its own.  Perhaps a proper understanding of the CLR type system would explain a few things.

posted on Thursday, December 4, 2008 8:03 AM
Filed Under [ .Net C# ]

Comments

No comments posted yet.

Post A Comment
Title:
Name:
Email:
Comment:
Verification: