DataRow.Field <T>(строка Column) генерирует недопустимое исключение приведения - PullRequest
7 голосов
/ 27 марта 2012

Добрый день,

IDE Visual Studio 2010 .NET 3,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 меньше и должно "соответствовать", верно?

Ответы [ 5 ]

11 голосов
/ 04 октября 2012

Если ваш столбец имеет значение nullable int, но вы пытаетесь присвоить ему int со значением по умолчанию 0:

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"); 
    }
}

Если ваш столбец имеет значение nullable int и вы хотите назначитьобнуляемому 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"); 
    }
}
6 голосов
/ 19 марта 2014

Согласитесь с ответом Ричарда, просто лучше использовать,

int iID = Convert.ToInt32(drSource["ID"]);
5 голосов
/ 27 марта 2012

Из любопытства, что произойдет, если вы сами явным образом приведете его из коллекции ключ / значение?

int iID = (int)drSource["ID"];
4 голосов
/ 27 марта 2012

В соответствии с реализацией расширения поля, ваше поле имеет значение 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;
    }
}
1 голос
/ 27 января 2017

Другой способ получить значение строки в переменной int - использовать объект и преобразовать его в Int32 следующим образом:

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

...