I have the following method:
public static T ExecuteScalar<T>(
string query,
SqlConnection connection,
params SqlParameter[] parameters) where T : new()
{
// Create SqlCommand
SqlCommand command = CreateCommand(query, connection, parameters);
// Execute command using ExecuteScalar
object result = command.ExecuteScalar();
// Return value as expected type
if (result == null || result is DBNull) return default(T);
return (T)result;
}
I want to have the MIN_ACTIVE_ROWVERSION of the database as an ulong. The strange thing is.. the First method call below generates an error but the second method call works fine.
Method call 1 generates an error:
ulong minActiveRowversion =
SqlUtils.ExecuteScalar<ulong>(
"SELECT CAST(MIN_ACTIVE_ROWVERSION() AS BIGINT)"
, _connectionString);
Error:
System.InvalidCastException: Specified cast is not valid.
Method call 2 works fine:
ulong minActiveRowversion =
(ulong)SqlUtils.ExecuteScalar<long>(
"SELECT CAST(MIN_ACTIVE_ROWVERSION() AS BIGINT)"
, _connectionString);
I don’t understand how that is possible because the result of the command.ExecuteScalar() method is this:
object result | 1955612
result.GetType() | {Name = "Int64" FullName = "System.Int64"}
- Can someone tell me why the first scenario is not possible and the second scenario works?
- Can someone tell me how I can solve it so I can use scenario 1.
Why
You can only unbox a value type to it’s original type. In your case, the cast first needs to go to
longfromobjectand then toulong.See this question for more detail:
Why can't I unbox an int as a decimal?
It also links a blog post by Eric Lippert.
How
One way, as you know, is to cast to the original type before casting to
T– unless, of course, the original type isT.As mentioned in the comments, another way is to use conversion routines (
Convert.ToUInt64) and not explicit casting.This could potentially be achieved using a
Func<object, T>:Making your call: