我有以下方法:
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;
}
我想将MIN_ACTIVE_ROWVERSION
数据库作为ulong
。奇怪的是..下面的第一个方法调用生成错误,但第二个方法调用工作正常。
方法调用1 生成错误:
ulong minActiveRowversion =
SqlUtils.ExecuteScalar<ulong>(
"SELECT CAST(MIN_ACTIVE_ROWVERSION() AS BIGINT)"
, _connectionString);
错误:
System.InvalidCastException: Specified cast is not valid.
方法调用2 正常工作:
ulong minActiveRowversion =
(ulong)SqlUtils.ExecuteScalar<long>(
"SELECT CAST(MIN_ACTIVE_ROWVERSION() AS BIGINT)"
, _connectionString);
我不明白这是怎么可能的,因为command.ExecuteScalar()
方法的结果是:
object result | 1955612
result.GetType() | {Name = "Int64" FullName = "System.Int64"}
答案 0 :(得分:5)
<强>为什么强>
您只能将值类型取消装入其原始类型。在您的情况下,演员首先需要从long
和然后到object
转到ulong
。
有关详细信息,请参阅此问题:
Why can't I unbox an int as a decimal?
它还链接了Eric Lippert的blog post。
如何强>
正如您所知,一种方法是在转换为T
之前转换为原始类型 - 当然,除非原始类型是 T
。
正如评论中所提到的,另一种方法是使用转换例程(Convert.ToUInt64
)而不是显式转换。
这可以使用Func<object, T>
:
public static T ExecuteScalar<T>(
Func<object, T> conversionFunctor,
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 conversionFunctor(result);
}
拨打电话:
ulong minActiveRowversion =
SqlUtils.ExecuteScalar<ulong>(
Convert.ToUInt64,
"SELECT CAST(MIN_ACTIVE_ROWVERSION() AS BIGINT)"
, _connectionString);
答案 1 :(得分:4)
亚当的回答正确地指出了问题;这是一个解决方案:只要可以使用内置或自定义转换将{@ 1}}转换为T
,就可以使用LINQ取消任何类型的转换。
static T UnboxUnchecked<T>(object obj) {
var pe = Expression.Parameter(typeof(object));
return Expression.Lambda<Func<object,T>>(
Expression.Convert(
Expression.Convert(pe, obj.GetType())
, typeof (T)
)
, pe
).Compile()(obj);
}
此方法生成一个LINQ表达式,该表达式首先将对象解包为其实际类型,然后应用转换。替换方法的最后一行
return (T)result;
与
return UnboxUnchecked<T>(result);
让它发挥作用。
以下是a link to an article,它解释了如何通过缓存已编译的lambdas来提高此类转换的效率。