简体   繁体   English

InvalidCastException long to ulong

[英]InvalidCastException long to ulong

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 . 我希望将数据库的MIN_ACTIVE_ROWVERSION作为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: 方法调用1生成错误:

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: 方法调用2工作正常:

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: 我不明白这是怎么可能的,因为command.ExecuteScalar()方法的结果是这样的:

object result       | 1955612
result.GetType()    | {Name = "Int64" FullName = "System.Int64"}
  1. Can someone tell me why the first scenario is not possible and the second scenario works? 有人能告诉我为什么第一种情况不可能,第二种情况有效吗?
  2. Can someone tell me how I can solve it so I can use scenario 1. 有人能告诉我如何解决它所以我可以使用方案1。

Why 为什么

You can only unbox a value type to it's original type. 您只能将值类型取消装入其原始类型。 In your case, the cast first needs to go to long from object and then to ulong . 在你的情况下,演员首先需要从object转到long 然后再到ulong

See this question for more detail: 有关详细信息,请参阅此问题:

Why can't I unbox an int as a decimal? 为什么我不能将int取消装入十进制?

It also links a blog post by Eric Lippert. 它还链接了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 is T . 如你所知,一种方法是在转换为T之前转换为原始类型 - 当然,除非原始类型 T

As mentioned in the comments, another way is to use conversion routines ( Convert.ToUInt64 ) and not explicit casting. 正如评论中所提到的,另一种方法是使用转换例程( Convert.ToUInt64 )而不是显式转换。

This could potentially be achieved using a Func<object, T> : 这可以使用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);
}

Making your call: 打电话:

ulong minActiveRowversion = 
    SqlUtils.ExecuteScalar<ulong>(
        Convert.ToUInt64,
        "SELECT CAST(MIN_ACTIVE_ROWVERSION() AS BIGINT)"
        , _connectionString);

Adam's answer correctly identifies the problem; 亚当的答案正确地确定了问题; here is a solution: you can use LINQ to unbox any type, as long as it can be cast to T with a built-in or a custom conversion. 这是一个解决方案:只要可以使用内置或自定义转换将其转换为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);
}

This method produces a LINQ expression that first unboxes the object to its actual type, and then applies the conversion. 此方法生成一个LINQ表达式,首先将对象解包为其实际类型,然后应用转换。 Replace the last line of your method 替换方法的最后一行

return (T)result;

with

return UnboxUnchecked<T>(result);

to make it work. 使它工作。

Here is a link to an article that explains how to make conversions of this kind more efficient by caching the compiled lambdas. 以下是一篇文章的链接,该文章解释了如何通过缓存已编译的lambda来提高此类转换的效率。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM