0

环境: Visual Studio 2015

时区: : UTC + 7:00, 曼谷

问题:在 DateTimeOffset 可为空的变量(DateTimeOffset?)上,使用 Null 条件运算符会导致异常,即即使值为 NULL,它仍会调用该方法,即(值作为 DateTimeOffset?)?.ToLocalTime(),它调用 ToLocalTime 和导致异常。

查询:我可以通过不使用 Null 条件运算符或使用 GetValueOrDefault 而不是运算符来解决它,但我想了解为什么它会在所有 UTC + TimeZones 中出现异常,它适用于 UTC - TimeZones

代码:

var dateTimeMinimum = DateTime.MinValue;
    var value = (object)dateTimeMinimum; // Mimic the WPF converter behavior
    var a1 = value as DateTimeOffset?; // This works
    if (a1 != null)// This works as it won't execute the code in the 'if'loop
    {
        var b1 = (a1 as DateTimeOffset?)?.ToLocalTime();
    }

var dto = (value as DateTimeOffset?)?.ToLocalTime() ?? (DateTime)value;// This breaks with following exception

在此处输入图像描述

编辑

我知道有很多方法可以修复代码,即

    DateTime dateTimeMinimum = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc);

这是我的查询,当我不使用空条件运算符时

var a1 = value as DateTimeOffset?;

它不会导致异常。是不是因为空条件运算符根据以下博客展开变量

http://www.ninjacrab.com/2016/09/11/c-how-the-null-conditional-operator-works-with-nullable-types/

我更感兴趣的是理解为什么当我使用空条件运算符时它会中断,而当我使用'as'运算符而不使用 DateTimeKind.Utc 进行简单转换时它会起作用

编辑2

这是 DateTimeOffset(.NET 框架代码)的构造函数,它在 ValidateOffset 方法处中断。来源- http://referencesource.microsoft.com/#mscorlib/system/datetimeoffset.cs,68b4bb83ce8d1c31

 // Constructs a DateTimeOffset from a DateTime. For Local and Unspecified kinds,
        // extracts the local offset. For UTC, creates a UTC instance with a zero offset.
        public DateTimeOffset(DateTime dateTime) {
            TimeSpan offset;
            if (dateTime.Kind != DateTimeKind.Utc) {
                // Local and Unspecified are both treated as Local
                offset = TimeZoneInfo.GetLocalUtcOffset(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime);
            }
            else {            
                offset = new TimeSpan(0);
            }
            m_offsetMinutes = ValidateOffset(offset);
            m_dateTime = ValidateDate(dateTime, offset);
        }
4

2 回答 2

1

问题是最小日期是 UTC 0,所以如果你想要那个但有一个正的 UTC,这意味着在 UTC 0 它将早于 minimum possible DateTime

简单地说,你不能创建这个(最小日期 UTC +1):

new DateTimeOffset(DateTime.MinValue, new TimeSpan(1, 0, 0))

因为这会DateTimeOffset为 UTC 时间 12 月 31 日-0001晚上 11:00 创建一个。

异常发生在这里:

var dto = <something null> ?? (DateTime)value;

正如dto推断的那样DateTimeOffset,你正在做(DateTimeOffset)(DateTime)value,然后是抛出异常的时候。该演员试图创建无法表示的负日期。

尝试此代码以确认该问题与空变量无关:

var dateTimeMinimum = DateTime.MinValue;
var value = (object)dateTimeMinimum; // Mimic the WPF converter behavior
DateTimeOffset dto = (DateTime)value;

更新

你仍然不相信我,试试这个:

var dto = (value as DateTimeOffset?)?.ToLocalTime() ?? new DateTimeOffset();

这不会失败。为什么?因为ToLocalTime没有被执行,也从来没有被执行过,而一直失败的是我告诉你的,从最小DateTimeDateTimeOffset正时区的演员表。


顺便说一句,您不能只使用运算符将​​ a 转换DateTime为 a ;这将始终返回 null。该运算符适用于兼容的类。DateTimeOffset?as

最后,即使解决了这个问题,我认为您的代码也难以理解和维护。你到底想在这里做什么?

于 2016-09-24T20:58:26.603 回答
0

这与可空运算符无关。

这将导致相同的错误:

var dto2 = new DateTimeOffset(dateTimeMinimum);

使用 DateTime.Min 时偏移量太大,如果将其更改为 DateTime.Now,则您的代码将起作用。

于 2016-09-24T20:40:46.483 回答