2016-01-26 4 views
1

Я пытаюсь определить разницу между DateTime и DateTime? используя отражение. Пожалуйста, ознакомьтесь со следующим кодом:C# Определить разницу между DateTime и DateTime? (Nullable)

public class TestClass 
    { 
     public DateTime testDate1 { get; set; } 
     public DateTime? testDate2 { get; set; } 
    } 

    public void Test() 
    { 
     TestClass testing = new TestClass(); 
     var props = typeof(TestClass).GetProperties(); 
     foreach (PropertyInfo p in props) 
     { 
      object o = p.GetValue(testing); 
      if (typeof(DateTime?).IsInstanceOfType(o)) 
      { 
       o = DateTime.Now; 
      } 
      if (typeof(DateTime).IsInstanceOfType(o)) 
      { 
       if (((DateTime)o) == DateTime.MinValue) 
       { 
        o = null; 
       } 
      } 
      Console.WriteLine(string.Format("{0} = {1}", p.Name, (o ?? "NULL").ToString())); 
     } 

    } 

Результат этого кода противоположный тому, что я ожидал бы. В настоящее время выход:

testDate1 = 26/01/2016 16:15:00

testDate2 = NULL

Я ожидаю testDate1 утратившими testDate2 содержать значение.

При отладке этого кода кажется, что первый проход, использующий testDate1, передает оба оператора typeof if, а второй - оба оператора if. Может ли кто-нибудь помочь мне понять и, надеюсь, попробовать и уловить конкретный экземпляр с нулевым значением даты времени?

Чтобы отметить, что я также попытался перейти к определению и проверке на Nullable на всякий случай, но это не имело значения.

Большое спасибо!

+0

Невозможно иметь тип с нулевым значением в коробке. Либо объект является DateTime, либо является нулевой ссылкой. –

+0

Я не уверен, что вы пытаетесь сделать здесь ... 'DateTime' - это структура, она не может иметь нулевое значение. Вот почему вам явно нужно использовать нотацию '?', Чтобы она была нулевой. –

+1

Возможно, вам будет интересно посмотреть это последнее сообщение: http://stackoverflow.com/questions/34938774/counterintuitive-design-of-addition-subtraction-between-numbers-and-nullable-num/34942047#34942047 – Ian

ответ

2

Во-первых, имейте в виду, что testDate1 никогда не может быть пустым, потому что DateTime является структура. Если вы объявите DateTime без его инициализации, он получит значение по умолчанию DateTime.MinValue. С другой стороны, testDate2 - это Nullable struct, где значение по умолчанию равно null (-ish ... это фактически значение, которое представляет собой null, но не null).

IsInstanceOfType использует o «s GetType() метод в фоновом режиме, чтобы убедиться в том, что его тип совпадает с типом вы сравниваете к (в данном случае, DateTime?). Тем не менее, если вы посмотрите на documentation, в нем говорится:

Вызов GetType на Nullable типа вызывает операцию бокса будет выполняться, когда тип неявно преобразуется в объект. Поэтому GetType всегда возвращает объект Type, который представляет базовый тип, а не тип Nullable.

Итак, если вы шаг через петлю Еогеасп для testDate1 собственности, вы увидите, что первое условие возвращает истину (с testDate1 не может быть нулевым, что означает, что имеет в быть типа DateTime). Затем вы переходите во второе условие if (хотя это действительно просто повторяет ту же проверку снова), но вы не вводите внутреннее, если потому, что o в настоящее время имеет значение DateTime.Now.

Теперь пошаговый для testDate2 (который держит нулевое значение), то вы увидите, что вы не входите либо КРП-условные, поскольку нуль не имеет типа. Таким образом, ваш объект будет оставаться нулевым во время второй итерации цикла, предоставляя вам вывод, который вы видите там.


ПРИМЕЧАНИЕ: Только так вы знаете, как вы «присвоение» значения в o не изменяет исходный TestClass на всех. Учитывайте следующее:

TestClass testing = new TestClass(); 
var prop = typeof(TestClass).GetProperty("testDate1"); 

// Here we get the current value of testing.testDate1, which is the default DateTime.MinValue 
object o = prop.GetValue(testing); 

// Here we set o to null... has ZERO effect on testing.testDate1. 
o = null; 

// What you actually want is probably the following. 
// (Remember though that testDate1 can't be null... this just sets it back to DateTime.MinValue.) 
prop.SetValue(testing, null); 
+0

'testDate2, с другой стороны, является нулевым объектом, поэтому его значение по умолчанию равно null.' Это «Nullable », а 'Nullable' является' struct', поэтому его значение по умолчанию равно * not * 'null' Это значение по умолчанию для 'Nullable' struct, которое происходит с * концептуально представляет *' null', хотя * это не null *. – Servy

+0

Хорошо, я обновил свой ответ, чтобы отразить это. Согласитесь ли вы, что концептуально вы можете рассматривать Nullable как объект в большинстве ситуаций? –

+0

Нет, вы не можете. И это * конечно * неправильно рассматривать его как таковое в этом примере, так как этот пример показывает, что 'Nullable' не только не действует как пользовательский класс, он даже не действует как нормальная структура. Существует специальное поведение компилятора * специально для типа с нулевым значением *, влияющее на поведение рассматриваемой программы, поэтому ** вы не можете рассматривать его как что-либо, кроме того, что именно это **. – Servy

2

Ответ вы не можете.

Если у вас есть object date, то нет способа узнать, исходит ли он от нулевого DateTime или нет.

DateTime? nullable = DateTime.Now; 
object o = nullable; 

Присваивание o морально эквивалентно

object temp = null; 

if (nullable.HasValue) 
{ 
    temp = nullable.Value; 
} 

o = temp; 

Как вы можете видеть, информация обнуляемого типа теряется и то, что вы действительно получаете это значение в штучной упаковке NULLABLE в.

Это легко увидеть, просто сделав o.GetType(), который вернет DateTime, если значение nullable имеет значение, или вы получите NullReferenceException, если это не так.

Это не означает, что вы не можете определить, является ли объявленный тип свойства, метода или члена нулевым или нет. Вы можете сделать это достаточно легко через отражение.

0

Благодарим за так много полезных комментариев и ссылок. Я понимаю, что это была собственность, которую я должен был проверять, а не объект. Я использую это:

Nullable.GetUnderlyingType(p.PropertyType) 

Это позволяет мне определить, с чем я имею дело, и довольно эффективен. Я все еще в конечном итоге включаю typeof (T) .Name, но я перейду через этот мост, когда я приеду к нему :)

Мне нужно жить с тем, что функциональный код против уродливого кода остается внутренней битвой!

Смежные вопросы