簡體   English   中英

InvalidCastException long to ulong

[英]InvalidCastException long to ulong

我有以下方法:

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"}
  1. 有人能告訴我為什么第一種情況不可能,第二種情況有效嗎?
  2. 有人能告訴我如何解決它所以我可以使用方案1。

為什么

您只能將值類型取消裝入其原始類型。 在你的情況下,演員首先需要從object轉到long 然后再到ulong

有關詳細信息,請參閱此問題:

為什么我不能將int取消裝入十進制?

它還鏈接了Eric Lippert的博客文章

怎么樣

如你所知,一種方法是在轉換為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);

亞當的答案正確地確定了問題; 這是一個解決方案:只要可以使用內置或自定義轉換將其轉換為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);

使它工作。

以下是一篇文章的鏈接,該文章解釋了如何通過緩存已編譯的lambda來提高此類轉換的效率。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM