ADO.NET конвертирует Decimal (4,2) в двойное использование Generics

Я пытаюсь преобразовать десятичное (4,2) поле, хранящееся в базе данных SQL Server, в С# ******, используя специальный метод, который преобразует поле в общий тип. (Метод является расширением класса SqlDataReader.)

Когда я запускаю код, я продолжаю получать ошибку "указанный приведение недействительно".

Здесь метод:

public static T Get<t>(this SqlDataReader reader, string field) 
{
 try {
 int index = reader.GetOrdinal(field);
 if (reader.IsDBNull(index)) return default(T);

 T item = (T)reader[index];
 return item;
 } catch (Exception e) {
 Console.WriteLine(e); 
 return default(T); 
 }
}
</t>

Когда я вызываю метод, я читаю значение прямо в конструкторе класса, например:

// reader is a SqlDataReader instance with an open connection, and fields obtained via the 'Read()' method.
MyClass myObject = new MyClass(reader.Get<******>("My_Field"));
</******>

SqlDataReader имеет в нем правильные данные. index переменная устанавливается на правильный порядковый номер поля, который, и когда в отладке я могу запустить линейный reader[1]; и получить правильное возвращаемое значение, например: 0 или 6.1.

Некоторыми значениями из базы данных, с которой она не справилась, являются: 0.00, 1.00, 6.1.

Я хотел бы выяснить, что вызывает эту проблему, и исправить ее в рамках универсального метода (который работал для всех других распространенных типов данных до сих пор), поскольку он был разработан для оптимизации ADO и упрощения чтения вместо регулярная божественная ужасная "котельная плита" ADO.

2 ответа

Вы не можете преобразовать десятичное число в коробке в двойное; вы должны сначала перенести его на распакованный десятичный знак. Вы можете использовать класс Convert, чтобы делать то, что вы пытаетесь сделать:

public static T Get<t>(this SqlDataReader reader, string field) 
{
 try {
 int index = reader.GetOrdinal(field);
 if (reader.IsDBNull(index)) return default(T);

 object item = reader[index];
 return item is T ? (T)item : (T)Convert.ChangeType(item, typeof(T));
 } catch (Exception e) {
 Console.WriteLine(e); 
 return default(T); 
 }
}
</t>

Я уверен, что в некоторых случаях это не обрабатывается, но этого должно быть достаточно, чтобы вы начали.


Проблема в том, что вы двойное кастинг (я, возможно, не буду использовать правильный термин здесь).

reader[index] возвращает object, который не может быть приведен к ****** непосредственно. Он должен быть отброшен до decimal.

decimal dec = 1.0M;
object obj = dec;

var x = (******)dec; //succeeds
var y = (******)obj; //fails

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

(******)reader.Get<decimal>("My_Field"))
</decimal>

licensed under cc by-sa 3.0 with attribution.