web-dev-qa-db-ja.com

DataRow.Field <T>(string Column)が無効なキャスト例外をスローします

良い一日、

[〜#〜] ide [〜#〜]Visual Studio 2010
。NET3.5
プラットフォームWinForms

SO質問 " DataRowからの値の取得の違い "が参照します。

[ID] INT IDENTITY(1, 1) NOT NULL PRIMARY KEY列のデータベーステーブルがあります。このテーブルをクエリしてローカル変数に値を格納すると、無効なキャスト例外が発生します。サンプルコード:

_string sQuery = @"
    SELECT [ID], [Description]
    FROM [Sources]
    ORDER BY [Description] ";

using (DataTable dtSources = SQLHelper.Fetch(sQuery))
{
    foreach (DataRow drSource in dtSources.Rows)
    {
        int iID = drSource.Field<int>("ID"); // InvalidCastException
        string sDescrption = drSource.Field<string>("Description");
    }
}
_

実行をステップ実行し、障害のある行で「クイックウォッチ」を実行すると、行をdrSource.Field<object>("ID")に変更することにより、セル値のタイプがshortではなくintのタイプであることがわかりました。テーブル定義で、これが明らかにintであるのに、なぜこれが発生するのでしょうか。さらに、shortはより小さく、正しく「適合する」必要があるため、intは暗黙的にshortに変換する必要がありますか?

8
that0th3rGuy

好奇心から、キー/値コレクションから明示的にキャストするとどうなりますか?

int iID = (int)drSource["ID"];
5
Richard

列がnull許容のintであるが、デフォルト値0でintに割り当てようとしている場合:

using (DataTable dtSources = SQLHelper.Fetch(sQuery))
{ 
    foreach (DataRow drSource in dtSources.Rows)'
    { 
        int iID = drSource.Field<int?>("ID") ?? 0; 
        string sDescrption = drSource.Field<string>("Description"); 
    }
}

列がnull許容のintであり、null許容のintに割り当てたい場合:

using (DataTable dtSources = SQLHelper.Fetch(sQuery))
{
    foreach (DataRow drSource in dtSources.Rows)
    {
        int? iID = drSource.Field<int?>("ID");
        string sDescrption = drSource.Field<string>("Description"); 
    }
}
11
Karen

リチャードの答えに同意してください。

int iID = Convert.ToInt32(drSource["ID"]);
7
Himalaya Garg

フィールド拡張の実装によると、フィールドにはDbNull値があります。

public static T Field<T>(this DataRow row, string columnName)
    {
        DataSetUtil.CheckArgumentNull<DataRow>(row, "row");
        return UnboxT<T>.Unbox(row[columnName]);
    }

UnboxTは、オブジェクトをTに変換するためのメソッドを提供するプライベートクラスです。この場合、ValueFieldコンバーターが使用されます。

private static class UnboxT<T>
{
    internal static readonly Converter<object, T> Unbox;

    static UnboxT()
    {
       DataRowExtensions.UnboxT<T>.Unbox =  
          new Converter<object, T>(DataRowExtensions.UnboxT<T>.ValueField);
    }

    private static T ValueField(object value)
    {
        if (DBNull.Value == value)
        {
            // You get this exception 
            throw DataSetUtil.InvalidCast(Strings.DataSetLinq_NonNullableCast(typeof(T).ToString()));
        }
        return (T) value;
    }
}
4

行の値をint変数に変換する別の方法は、「object」を使用して、次のようにInt32に変換することです。

int iID = Convert.ToInt32(row.Field<object>("ID"));

1