【问题标题】:why c# disallows to assign SqlDatetime.MinValue to datetime but allows comparison为什么 c# 不允许将 SqlDatetime.MinValue 分配给 datetime 但允许比较
【发布时间】:2015-06-03 02:56:14
【问题描述】:

以下代码使用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.

我的问题是为什么在SqlDateTimeDatetime 类型之间允许comparison 而不是assignment。 (除非comparison 运营商正在做一些implicit 转换。)

我猜我一定遗漏了一些非常基本的东西。

【问题讨论】:

  • 您怀疑比较会导致隐式转换是正确的。请参阅下面的答案以了解原因。

标签: c# datetime sqldatetime


【解决方案1】:

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;

【讨论】:

  • 既然我将dateTimeVariableSqlDateTime 进行比较,它不应该尝试将SqlDateTime 隐式转换为DateTime 而不是反之亦然吗? (因为它在> 运算符的左侧,类似于= 运算符无法进行隐式转换?
  • 是的,我只是在类比。由于DateTime ">" SqlDateTime "comparison" 成功(可能是由于隐式转换(?)。我猜SqlDateTime 的位置在right 上,它应该尝试将SqlDateTime 转换为DateTime),我假设 DateTime "=" SqlDateTime "assignment" 也应该成功。(理论上)
【解决方案2】:

这是一个潜在的精度损失问题。这通常发生在“缩小”与“扩大”的上下文中。

整数是数字的子集。所有整数都是数字,有些数字不是整数。因此,“数字”类型比“整数”类型更宽。

您始终可以将类型分配给更广泛的类型,而不会丢失信息。

收窄是另一回事。要将 1.3 分配给整数,您必须丢失信息。这是可能的,但编译器不会执行缩小转换,除非您明确声明这是您想要的。

因此,需要扩大转换的赋值会自动隐式转换,但缩小赋值需要显式转换或转换(并非所有转换都是简单转换)。

虽然可以说SqlDateTimeDateTime 窄,但表示差异意味着两个 方向的转换都可能有损失。因此,要将 SqlDateTime 分配给 DateTime 需要显式转换。严格来说,将 DateTime 转换为 SqlDateTime 应该需要显式转换,但在 SqlDateTime 类型中实现的隐式转换(qv Grant 的回答)使得 SqlDateTime 表现 就好像它更宽了。我错误地假设 SqlDateTime 更广泛,因为这就是它在这种情况下的行为方式,并且许多评论者对挑选出这个重要的微妙之处表示赞赏。

这种隐式转换的事情实际上是 VARCHAR 列和 ADO.NET 隐式类型参数的一个问题,因为 C# 字符串是 Unicode 并且变成了 NVARCHAR,所以将它们与 VARCHAR 类型的索引列进行比较会导致扩大转换为NVARCHAR(隐式扩大转换也发生在 TSQL 中),它可以防止使用索引 - 这不会阻止查询返回正确的结果,但会削弱性能。


来自 MSDN

SqlDateTime 结构

表示日期和时间数据,取值范围从 1753 年 1 月 1 日到 9999 年 12 月 31 日,精度为 3.33 毫秒,可存储在数据库中或从数据库中检索。 SqlDateTime 结构具有与其对应的 .NET Framework 类型 DateTime 不同的基础数据结构,它可以表示 12:00:00 AM 1/1/0001 和 11:59:59 PM 12/31/9999 之间的任何时间精度为 100 纳秒。 SqlDateTime 实际上存储到 00:00:00 AM 1/1/1900 的相对差异。因此,从“00:00:00 AM 1/1/1900”到整数的转换将返回 0。

【讨论】:

  • 喜欢你的解释,但有一件事是错误的。 SqlDateTime 分配给 DateTime 不需要显式强制转换。这就是 Value 属性的用途
  • "SqlDateTime 比 DateTime 宽?"我不确定这是否正确。您是指内存使用量还是它可以容纳的价值?
  • @ManuelZelenka - SqlDateTime 不需要显式转换为 DateTime 是正确的。强制转换与转换并不完全相同,转换是 SqlDateTime.Value getter 方法所做的。我已经更正了答案文本。
  • @ANewGuyInTown - 我从 MSDN 添加了一些信息来澄清这一点。你是对的,严格来说 DateTime 更宽。但由于内部表示形式的根本不同,两个方向的转换都可能有损失。
猜你喜欢
  • 1970-01-01
  • 2023-04-02
  • 2010-11-13
  • 1970-01-01
  • 2021-04-19
  • 2011-12-20
  • 2021-11-01
  • 2019-03-11
  • 1970-01-01
相关资源
最近更新 更多