具有可为空 DateTimeOffset 的空条件运算符

Null conditional operator with nullable DateTimeOffset

环境: Visual Studio 2015

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

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

Query:我可以通过不使用 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);

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

var a1 = value as DateTimeOffset?;

不会导致异常。是因为 null 条件运算符根据以下博客

展开变量

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

我更想了解为什么当我使用 null 条件运算符时它会中断,而当我使用 'as' 运算符而不使用 DateTimeKind.Utc

时它会在我进行简单转换时起作用

EDIT2:

这是 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);
        }

这与可空运算符无关。

这会导致同样的错误:

var dto2 = new DateTimeOffset(dateTimeMinimum);

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

问题是最短日期在 UTC 0,所以如果你想要那个 但 UTC 为正 ,这意味着在 UTC 0 它将早于最小可能 DateTime.

简而言之,您无法创建此(最小日期 UTC +1):

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

因为这将为 12 月 31 日 -0001 11:00PM UTC 创建一个 DateTimeOffset

异常恰好发生在这里:

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 没有被执行而且从来没有被执行 ,而一直失败的是我告诉你的,从最小值 DateTime 到 [=15= 的转换] 正时区。


顺便说一句,您不能只使用 as 运算符将 DateTime 转换为 DateTimeOffset?;那将始终 return 为空。该运算符用于兼容类。

最后,即使修复了这个问题,我也觉得你的代码太难理解和维护了。你到底想在这里做什么?