Я столкнулся с ошибкой: «Невозможно привести объект типа «System.Int16» к типу «System.Int32». Не слишком ли это нелогично? Почему? Когда я пробую следующее в непосредственных окнах, результат такой:
reader.GetInt16(mycolumn_ordinal_value)
999
reader.GetInt32(mycolumn_ordinal_value)
Exception thrown: 'System.InvalidCastException' in Microsoft.Data.SqlClient.dll
На уровне БД (sqlserver) он определяется как mycolumn smallint.
Когда я спрашиваю об этом Github Copilot, он буквально говорит:
Однако, когда вы пытаетесь использовать
reader.GetInt32(mycolumn), выдается сообщениеSystem.InvalidCastException. Это необычно (вы не можете быть серьезным, чувак!!), потому чтоGetInt32должен иметь возможность обрабатывать любое значение, которое может обрабатыватьGetInt16, поскольку диапазон 32-битного целого числа (от-2,147,483,648до2,147,483,647) равен намного больше.
Я этого не понимаю. Есть идеи?
Логично, если поле имеет другой тип или вы пытаетесь сохранить значение в поле неправильного типа. Мы не можем гадать. Вместо случайно сгенерированных ответов публикуйте свой собственный код, запрос, схему таблицы и фактический полный текст исключения, а не только сообщение.
Предполагая, что это SqlDataReader, такое поведение задокументировано в разделе «Примечания» — «Преобразования не выполняются; следовательно, полученные данные уже должны быть 32-битным целым числом со знаком».
Генераторы случайного текста ничего не знают ни об ADO.NET, ни о чем-либо еще. Они знают только о статистике словосочетаний. Они даже не придадут большего значения документации или реализации ADO.NET. Они будут придавать такой же вес копипасте или другим случайно сгенерированным плохим статьям, например тем, которые можно найти на… определенных сайтах.
Что слева? Вы присваиваете результат вызова int, long или чему-то еще?
Это происходит потому, что когда вы вызываете SqlDataReader.GetInt32() для short, он в конечном итоге вызывает внутренний код, например return (Int32)this.Value, где this.Value — это упакованный short, и именно здесь возникает исключение.
@MatthewWatson, не могли бы вы написать ответ, я хочу его принять. Я попробовал смоделировать это, как вы говорите var a = (Int32)(object)(short)5;
@PanagiotisKanavos это не имеет ничего общего с каким-либо ORM.
@SonerfromTheOttomanEmpire Я ничего не говорил об ORM. ADO.NET — это библиотека доступа к данным .NET. SqlDataReader является частью ADO.NET, фактически до недавнего времени он был упакован в саму среду выполнения. Лишь недавно он был извлечен в библиотеку Microsoft.Data.SqlClient.





Это происходит потому, что когда вы вызываете SqlDataReader.GetInt32() для короткого замыкания, он в конечном итоге вызывает внутренний код, например return (Int32)this.Value, где this.Value — это короткое замыкание в штучной упаковке, и именно здесь возникает исключение.
Мы можем посмотреть исходный код SqlDataReader.GetInt32():
override public Int32 GetInt32(int i) {
ReadColumn(i);
return _data[i].Int32;
}
Это _data массив типа SqlBuffer. Определение SqlBuffer.Int32 следующее:
internal Int32 Int32 {
get {
ThrowIfNull();
if (StorageType.Int32 == _type) {
return _value._int32;
}
return (Int32)this.Value; // anything else we haven't thought of goes through boxing.
}
}
Здесь важно то, что, поскольку тип хранилища не совпадает, оно возвращает (Int32)this.Value. В данном случае this.Value имеет тип объекта и на самом деле является коробочной версией этого фактического базового типа — в вашем примере это Int16.
Следовательно, он пытается привести упакованный Int16 к Int32 и выдает исключение.
Я готов поспорить, что это не имеет ничего общего с кастингом, а связано только с боксом. Хотя неявное приведение от
int16кint32доступно, вы не можете распаковатьint16кint32.