Почему C# запрещает назначать SqlDatetime.MinValue для datetime, но позволяет сравнивать
Следующий код прекрасно компилируется с comparison
оператор.
If(dateTimeVariable > SqlDateTime.MinValue) //compiles Ok. dateTimeVariable is of type DateTime
{
}
Однако следующий код не компилируется.
DateTime dateTimeVariable=SqlDateTime.MinValue;
//Throws exception , cannot convert source type SqlDateTime to DateTime. Which is obvious.
Мой вопрос почему comparison
разрешено между SqlDateTime
а также Datetime
типы, но не assignment
, (Если не comparison
операторы делают некоторые implicit
преобразования.)
Я предполагаю, что я должен упустить что-то действительно простое.
2 ответа
Это вопрос потенциальной потери точности. Обычно это происходит в контексте "сужения" против "расширения".
Целые числа являются подмножеством чисел. Все целые числа являются числами, некоторые числа не являются целыми числами. Таким образом, тип "число" шире, чем тип "целое число".
Вы всегда можете назначить тип более широкому типу без потери информации.
Сужение это другое дело. Чтобы присвоить 1.3 целое число, вы должны потерять информацию. Это возможно, но компилятор не будет выполнять сужающее преобразование, если вы явно не укажете, что это то, что вам нужно.
В результате, назначения, которые требуют расширенного преобразования, автоматически и неявно преобразуются, но сужающие назначения требуют явного преобразования или преобразования (не все преобразования являются простым преобразованием).
Хотя возможно SqlDateTime
уже чем DateTime
Различия в представлении означают, что преобразования в обоих направлениях потенциально являются потерями. В результате для присвоения SqlDateTime DateTime требуется явное преобразование. Строго говоря, преобразование DateTime в SqlDateTime должно требовать явного преобразования, но неявное преобразование, реализованное в типе SqlDateTime (ответ qv Grant), заставляет SqlDateTime вести себя так, как если бы оно было шире. Я сделал ошибку, предположив, что SqlDateTime был шире, потому что именно так он себя ведет в этом случае, и многие благодарят комментаторов за выбор этой важной тонкости.
Эта вещь неявного преобразования на самом деле представляет собой небольшую проблему со столбцами VARCHAR и неявно типизированными параметрами ADO.NET, потому что строки C# имеют Unicode и становятся NVARCHAR, поэтому сравнение их с индексированным столбцом типа VARCHAR приведет к расширению преобразования в NVARCHAR (в TSQL также происходит неявное расширение с расширением (что может помешать использованию индекса - что не помешает запросу вернуть правильные результаты, но снизит производительность).
Из MSDN
Структура SqlDateTime
Представляет данные даты и времени в диапазоне значений с 1 января 1753 года по 31 декабря 9999 года с точностью до 3,33 миллисекунды для хранения или извлечения из базы данных. Структура SqlDateTime имеет базовую структуру данных, отличную от соответствующего типа.NET Framework, DateTime, который может представлять любое время между 12:00:00 1 января 2001 года и 11:59:59 31 декабря 1999 года. точность 100 наносекунд. SqlDateTime фактически сохраняет относительную разницу до 00:00:00 1 января 1900 года. Поэтому преобразование из "00:00:00 AM 01.01.1900" в целое число вернет 0.
Там неявное преобразование в SqlDateTime
который заботится о преобразовании DateTime
для SqlDateTime
без дополнительной работы:
public static implicit operator SqlDateTime(DateTime value)
{
return new SqlDateTime(value);
}
// SqlDateTime mySqlDate = DateTime.Now
Что должно происходить, так это dateTimeVariable
в настоящее время неявно преобразуется из DateTime
для SqlDateTime
для сравнения:
if (dateTimeVariable > SqlDateTime.MinValue)
{
// if dateTimeVariable, after conversion to an SqlDateTime, is greater than the
// SqlDateTime.MinValue, this code executes
}
Но в случае следующего кода нет ничего, что позволяло бы вам просто SqlDateTime
в DateTime
переменная, так что это не позволяет.
DateTime dateTimeVariable = SqlDateTime.MinValue; // fails
Приведите исходное значение, и оно будет скомпилировано, но есть вероятность, что вы потеряете некоторую ценную информацию, которая является частью SqlDateTime
но не DateTime
,
DateTime dateTimeVariable = (DateTime)SqlDateTime.MinValue;