2014-12-08 2 views
0

Некоторые предпосылки для понимания кода. У меня есть приложение MVC, все мои модели реализуют IModel. IModel просто принудительно использует свойство Id.Сравнение двух равных варов возвращает false

Следующий способ «обновляет» экземпляры модели с данными, доступными в режиме просмотра. Для каждого свойства viewmodel он проверяет, существует ли соответствующее свойство в модели, если оно оно обновляет значение в модели с параметрами модели viewmodel, если значения разные.

В последнем пункте это идет не так. Заявление: OldValue! = NewValue всегда возвращает true, даже если f.e. оба являются целыми числами, 1. Почему?

public static Boolean UpdateIfChanged<M, VM>(this M Model, VM ViewModel) where M : IModel 
{ 
    Boolean HasUpdates = false; 
    Type Mtype = typeof(M); 
    PropertyInfo[] MProperties = Mtype.GetProperties(BindingFlags.Public | BindingFlags.Instance); 
    Type VMtype = typeof(VM); 
    PropertyInfo[] VMProperties = VMtype.GetProperties(BindingFlags.Public | BindingFlags.Instance); 

    foreach (var VMProperty in VMProperties) 
    { 
     if (!VMProperty.PropertyType.GetInterfaces().Any(x => x.Name == typeof(IModel).Name) 
      && MProperties.Any(x => x.Name == VMProperty.Name) 
      && Mtype.GetProperty(VMProperty.Name).PropertyType == VMProperty.PropertyType) 
     { 
      var OldValue = Mtype.GetProperty(VMProperty.Name).GetValue(Model); 
      var NewValue = VMtype.GetProperty(VMProperty.Name).GetValue(ViewModel); 
      if (NewValue != null) 
      { 
       if (OldValue == null) 
       { 
        Mtype.GetProperty(VMProperty.Name).SetValue(Model, NewValue); 
        HasUpdates = true; 
       } 
       else 
       { 
        if (OldValue != NewValue) 
        { 
         Mtype.GetProperty(VMProperty.Name).SetValue(Model, NewValue); 
         HasUpdates = true; 
        } 
       } 
      } 
     } 
    } 
    return HasUpdates; 
} 

ответ

2

Проблема здесь состоит в том, что OldValue и NewValue являются object s во время компиляции, а не int, и поэтому операторы ==/!= называют те, которые определены в object классе, потому что all operators are static. В object операторы проверить ссылочной равенства, а не логическое равенство, и, таким образом, только проверить, если два аргумента точно такой же объект (тот же указатель в C++)

Чтобы обойти эту проблему, у вас есть несколько вариантов

  • Как уже упоминалось Tigran, типа отливать значение выходит, так что вы в конечном итоге с помощью оператора, определенного в int вместо object
  • Зова object.Equals(OldValue, NewValue), который проверяет нуль, а затем вызывает virtualObject.Equals(object o), который, таким образом, будет вызывать функцию, определенную в самом классе/структуры вызывающего объекта (в данном случае int)
+1

Я бы предложил использовать 'object.Equals (OldValue, NewValue) ', который обрабатывает null-check для вас. –

+0

Согласен, я скорректировал свой ответ таким образом – David

1

вашего ПолучитьЗначение (..) возвращает вызов коробочных целогообъекта, так ссылочный типа.

Поэтому ваш код:

//OldValue and NewValue are Object types and NOT integers ! 
if (OldValue != NewValue) 

сравнивает ссылки и не значения.

Вы не заметили, что при использовании ключевого слова var, которое «скрывает» конкретный тип.

Чтобы правильно решить эту проблему, можно сделать так:

.... 
var OldValue = (int)Mtype.GetProperty(VMProperty.Name).GetValue(Model); //cast to int 
var NewValue = (int)VMtype.GetProperty(VMProperty.Name).GetValue(ViewModel);//cast to int 
.... 
+0

Возвращаемый тип GetValue может быть много разных вещей, поэтому литье в int не является решением. Но ваш комментарий к «коробке» был замечательным, чтобы понять, почему это пошло не так. – BrilBroeder

+0

@BrilBroeder: литье в 'int' связано с * этим * конкретным вопросом, где OP утверждает, что ожидаемый тип данных должен быть' int'. – Tigran

0

Попробуйте if (OldValue.ToString() != NewValue.ToString()). Или, если OldValue/NewValue являются ИНТ-s: if ((int)OldValue != (int)NewValue)

0

Лучше синтаксис будет:

if (!Equals(OldValue, NewValue))