Почему 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;
Другие вопросы по тегам