User98743 Ответов: 1

Не удается преобразовать тип объекта в тип long


День 3 пытаюсь решить эту проблему.

Я пытаюсь установить переменную в C#, равную значениям, которые я получаю из базы данных, как я делал сотни раз. Я буквально понятия не имею, что делаю не так.

Моя проблема заключается в DBToType<t> при итерации DataTable.Строки, чтобы получить поле из ItemArray.

for ( int i = 0 ; i < dt.Rows.Count - 1 ; i++ ) //Looping through rows
{
	long COLUMN_PROPID = DBToType<long>( dt.Rows[i].ItemArray[5] ); 
}


DBToType производит "невозможно преобразовать из типа object в тип long"


/// <summary>
		/// Converts DB types to C# Types and ensures that DBNull gets converted to the default value for the type.
		/// </summary>
		/// <typeparam name="T">The expected return type</typeparam>
		/// <param name="value">The value of a column, straight form the database provider</param>
		/// <returns>The value as its coorisponding C# Type, with DBNull converted to the default value of the type. </returns>
		public T DBToType<T> ( T value )
		{
			if ( !Convert.IsDBNull ( value ) )
			{
				return ( T ) Convert.ChangeType ( value , typeof ( T ) );
			}
			else
			{
				return default ( T );   //returns the default for the type... not null
			}
		}


Что я уже пробовал:

Все под солнцем...

Это была моя первая попытка решить эту проблему с помощью универсального метода.

1 Ответов

Рейтинг:
2

BillWoodruff

Чтобы исключить возможность того, что вы получаете объект, который не может быть преобразован в длинный, проверьте его с помощью другой функции, использующей Int64.TryGetValue, и перерыв на ошибки, чтобы исследовать данные.

Я бы предпочел использовать жестко закодированные методы преобразования конкретных типов, которые выбрасывают полезные ошибки. Использование 'ChangeType стоит дорого. Вот пример типа метода расширения, который я использую:

public static class ConversionExtensions
{
    public static Int32 ToInt(this string str, bool doThrowOnError = true, int defaultValue = Int32.MinValue)
    {
        int i;

        if (Int32.TryParse(str, out i))
        {
            return i;
        }

        if (doThrowOnError)
        {
            throw new ArgumentException($"{str} is not convertible to Int32");
        }

        return defaultValue;
    }
}
Если вы хотите "перейти на общий язык", то попробуйте что-то вроде этого:
using System.ComponentModel; // required

// written quickly: not fully tested
public T2 DbTypeConverter<T1,T2>(T1 value)
{
    if (value == null || Convert.IsDBNull(value))
    {
        return default(T2);
    }

    TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(T2));

    if (typeConverter.CanConvertFrom(typeof(T1)))
    {
        try
        {
            return (T2) Convert.ChangeType(value, typeof(T2));
        }
        catch (Exception ex)
        {
            switch (ex.GetType().Name)
            {
                // fill these in with meaningful actions !
                case "InvalidFormatException":
                    break;
                case "InvalidCastException":
                    break;
                case "FormatException":
                    break;
                case "OverflowException":
                    break;
                case "ArgumentException":
                    break;
            }
        }
    }

    return default(T2); //returns the default for the type... not null
}

// simple tests
    // long lng1 = DbTypeConverter<string, long>("57657777");
    
    // long lng2 = DbTypeConverter<string, long>("34.45");
    
    // long lng3 = DbTypeConverter<string, long>(DateTime.Now.ToString());
Хорошая информация о том, что вы можете и не можете делать с TypeConverter: [^]


User98743

Привет, Билл, я хотел перейти на общий язык только потому, что в наши дни мне казалось обычной практикой избегать нескольких методов, которые делают одно и то же, но для разных типов данных. Однако я не был уверен, почему я не получаю полезных сообщений об ошибках, пока вы не упомянули об этом, поэтому я думаю, что мне будет лучше сделать это. Тем не менее, это 4-й день попытки исправить это, так что все, что работает, я буду внедрять сегодня и улучшать позже. Я ценю ваши отзывы и приму ваш ответ позже.

BillWoodruff

Рад, что вы получили некоторые идеи от этого Рика; это было "образовательно" для меня, чтобы снова посетить этот вопрос. Хотя дженерики-это глубоко полезный инструмент, в ситуациях, когда вы уверены, что имеете дело с дискретным набором типов, вы получаете большую производительность, imho, и более поддерживаемый код, жестко кодируя методы каждого типа.

Учитывая реляционную базу данных со схемой фиксированных типов, я бы предположил, что стратегия преобразования неродовых типов будет более подходящей ... ваш пробег может варьироваться.

твое здоровье, Билл

User98743

В конце концов, я решил пойти строго типизированным маршрутом. В принципе, я просто продублировал все методы OleDbDataReader GetType, такие как GetInt32(x) и т. д., Так что теперь они доступны мне без необходимости открытого datareader, который, как я прочитал, требует эксклюзивной блокировки базы данных. Дженерики существуют уже много лет, но с тех пор, как я был классическим разработчиком asp еще в ледниковые периоды, я изо всех сил стараюсь быть в курсе этого и многого другого. Спасибо за вашу помощь!

BillWoodruff

Пожалуйста, Рик. Я приложил пример методов расширения, которые я использую, к ответу выше.