2016-09-24 2 views
0

Environnement: Visual Studio 2015opérateur nul conditionnel avec DateTimeOffset annulable

Fuseau horaire:: UTC + 7:00, Bangkok

Problème: Sur DateTimeOffset annulable varialbe (? DateTimeOffset), la l'utilisation de l'opérateur Null conditionnel entraîne une exception, c'est-à-dire qu'elle appelle la méthode même si la valeur est NULL (valeur en tant que DateTimeOffset?)? ToLocalTime(), elle appelle ToLocalTime et entraîne une exception.

Recherche: Je peux le résoudre par ne pas utiliser l'opérateur conditionnel nul ou à l'aide du GetValueOrDefault au lieu de l'opérateur, mais je veux comprendre pourquoi il Resutls en exception avec tous UTC + TimeZones, il fonctionne bien avec UTC - TimeZones

code:

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 

enter image description here

EDIT:

Je crois savoir qu'il ya plusieurs façons de corriger le code-à-dire

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

Voici ma requête si, quand je ne l'utilise l'opérateur conditionnel null

var a1 = value as DateTimeOffset?; 

Il ne entraîner une exception. Est-ce parce que l'opérateur conditionnel null unwraps la variable par la suite Blog

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

Je suis plus intéressé à comprendre pourquoi il se casse lorsque j'utilise l'opérateur nul conditionnel et fonctionne quand je rejetterai simple, si vous utilisez le « comme » opérateur sans utiliser le DateTimeKind.Utc

EDIT2:

C'est le constructeur de DateTimeOffset (.NET code-cadre) et il se casse à la méthode ValidateOffset. Source - 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); 
     } 
+0

Quelle est la valeur du décalage lorsque cette exception a été levée? Le message d'erreur semble suggérer que l'année résultante était soit inférieure à 0 ou supérieure à 10K – pquest

+0

DateTime.MinValue –

+0

qui est la valeur du décalage? – pquest

Répondre

1

Le problème est que la date minimum est à UTC 0, donc si vous voulez que mais avec un UTC positif, cela signifie qu'à UTC 0 il sera plus tôt que le minimum possible DateTime.

Pour le mettre simplement, vous ne pouvez pas créer cette (date +1 UTC minimum):

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

Parce que cela créerait un DateTimeOffset pour le 31 décembre -0001 11:00 UTC PM.

L'exception se produit exactement ici:

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

Comme dto est inférée comme DateTimeOffset, il vous faites (DateTimeOffset)(DateTime)value, et est alors lorsque l'exception est levée. Cette distribution tente de créer la date négative, qui ne peut pas être représentée.

Essayez ce code pour confirmer que la question est pas liée à une variable nulle:

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

MISE À JOUR

Comme vous ne me croyez pas, essayez cette :

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

Cela n'échouera pas. Pourquoi? Parce que ToLocalTime est n'est pas en cours d'exécution et n'a jamais été, et ce qui a échoué tout ce temps était ce que je vous ai dit, la fonte du minimum DateTime à DateTimeOffset avec le fuseau horaire positif.


BTW, vous ne pouvez pas convertir un DateTime à un DateTimeOffset? avec l'opérateur as; cela retournera toujours null. Cet opérateur est pour les classes compatibles. En fin de compte, même en corrigeant cela, je pense que votre code est trop difficile à comprendre et à maintenir. Qu'est-ce que vous essayez exactement de faire ici?

+0

C'est ce que je veux une valeur NULL et pour cela j'utilise l'opérateur conditionnel Null. Si c'est Null, j'essaye de l'analyser en DateTime. –

+0

var dto = (valeur comme DateTimeOffset?) ?. ToLocalTime() ?? (DateTime) valeur; –

+0

Mais ce n'est pas nul, vous obtenez une exception ... UTC Minimum DateTime converti en LocalTime (UTC +7) lève cette exception. Aucun problème null lié. – Andrew

0

Cela n'a rien à voir avec l'opérateur annulable.

Cela entraînera la même erreur:

var dto2 = new DateTimeOffset(dateTimeMinimum); 

Le décalage est trop grand lorsque vous utilisez DateTime.Min, si vous changez à DateTime.Now, votre code fonctionnera.

+0

Merci pour la réponse. Si vous voyez la variable a1 dans mon code, il en résulte une valeur NULL et l'exécution ne sera pas entrée si block. De même si la variable "value" est castée en DateTimeOffset ?, elle devrait être NULL, elle ne devrait pas entraîner d'exception. –

+0

L'opérateur as dans ce cas retournera toujours NULL car vous essayez de convertir entre DateTime et DateTimeOffset qui sont des classes non liées, tandis que l'opérateur NULL essaie d'obtenir la valeur. Je ne suis pas si familier avec "derrière la scène" de l'opérateur null Roslyn mais je crois que votre ligne agit comme une distribution explicite –