2010-01-15 4 views
23

Мне нужно знать, как вы проверяете, изменился ли объект. В основном мне нужно что-то вроде свойства, которое называется TrackChanges, когда я устанавливаю его true один раз, и если какие-либо данные в этом объекте «изменены», метод на том же объекте (IsObjectChanged) может вернуть true.Какова наилучшая практика для проверки того, изменился ли объект?

Вам когда-нибудь понадобилось такое и как вы его разрешили? Я не хочу изобретать колесо, если для такого сценария уже есть лучшая практика?

Я думал клонировать объект, прежде чем я вызову TrackChange = true в его сеттер. И когда я вызываю IsObjectChanged() Используя отражение, я сравню все значения его публичного поля с клонированной копией. Я не уверен, что это хороший способ.

Рекомендации:

спасибо, Бурак Оздоган

+0

возможный дубликат [Что это лучший способ сказать, если объект изменяется?] (Http://stackoverflow.com/questions/34809/what- is-the-best-way-to-tell-if-an-object-is-modified) – mathieu

ответ

16

Когда мне нужно отслеживать изменения свойств на мои объекты для тестирования я подключить обработчик событий на объектах PropertyChanged событие. Это поможет вам? Затем ваши тесты могут делать любое действие, которое они хотят, на основе изменения. Обычно я подсчитываю количество изменений и добавляю изменения в словари и т. Д.

Для этого ваш класс должен реализовать интерфейс INotifyPropertyChanged. Тогда каждый может прикрепить и слушать измененные свойства:

public class MyClass : INotifyPropertyChanged { ... } 

[TestFixture] 
public class MyTestClass 
{ 
    private readonly Dictionary<string, int> _propertiesChanged = new Dictionary<string, int>(); 
    private int _eventCounter; 

    [Test] 
    public void SomeTest() 
    { 
     // First attach to the object 
     var myObj = new MyClass(); 
     myObj.PropertyChanged += SomeCustomEventHandler; 
     myObj.DoSomething(); 
     // And here you can check whether the object updated properties - and which - 
     // dependent on what you do in SomeCustomEventHandler. 

     // E.g. that there are 2 changes - properties Id and Name changed once each: 
     Assert.AreEqual(2, _eventCounter); 
     Assert.AreEqual(1, _propertiesChanged["Id"]); 
     Assert.AreEqual(1, _propertiesChanged["Name"]); 
    } 

    // In this example - counting total number of changes - and count pr property. 
    // Do whatever suits you. 
    private void SomeCustomEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
    { 
     var property = e.PropertyName; 
     if (_propertiesChanged.ContainsKey(property)) 
      _propertiesChanged[property]++; 
     else 
      _propertiesChanged[property] = 1; 

     _eventCounter++; 
    } 
} 
+0

Ницца! Вопросы Bur: 1) Что считается «изменением»? В msdn говорится, что он вызывается при вызове сеттера. Поэтому мне все еще нужно проверить, отличается ли оно от предыдущего значения, правильно? 2) Что делать, если свойство этого объекта является ссылкой на другой тип объекта, и если свойство этого объекта изменено, я считаю, что этот случай становится намного сложнее. что-то вроде: myPerson.Address.Ctiy = "aDifferentCityName" – pencilCake

+0

Изменение - событие PropertyChanged. Внедряя интерфейс INotifyPropertyChanged, вам нужно инициировать события самостоятельно. Когда вы сами это контролируете, вы можете в основном выбрать, хотите ли вы, чтобы изменение на одно значение считалось изменением. Я не. – stiank81

+0

Если у MyObject есть свойство, которое ссылается на другой объект, и вы хотите, чтобы события PropetyChanged, когда этот один был изменен, также MyObject должен перехватить событие PropertyChanged на его ссылочном объекте и вызвать событие с измененным событием для его передачи. Это, конечно, усложняется - сначала это может быть сложно, но на самом деле это не так сложно, когда вы это понимаете. Удачи! – stiank81

3

Бурак,

Вы можете взглянуть на Entity Framework или другие рамки Microsoft. Вы можете видеть события, такие как PropertyChanging или PropertyChanged.

Посмотрите на сгенерированный код.

Вы могли бы взглянуть на код NHibernate, а также, но так как база кода настолько огромен, лучше смотреть на генераторах Microsoft ORM ..

0

Вместо того, чтобы создать свойство вы должны создать событие и назовите его чем-то вроде OnChanged.

1

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

Как показано выше, вы можете использовать INotifyPropertyChanged, чтобы узнать, какие свойства были изменены в вашем объекте.

+1

Для простого сравнения потребуется создание (глубокой) копии вашего объекта. Это дорого и в памяти, и во времени. –

2

Внедрить и использовать интерфейс INotifyPropertyChanged. Классный способ сделать это без строковых литералов - here.

4

Это две части. События для уведомления об изменении - это одна часть, но сохранение истории - еще одна важная вещь. Entity Framework делает это тоже (как LINQ to SQL), и я реализовал это и в своем собственном коде. Как минимум, у вас есть флаг для члена, чтобы сказать, что он изменился. В зависимости от ваших требований вы также можете сохранить исходное значение. Обычно это становится задачей отдельного объекта. Entity Framework сохраняет отслеживание изменений в отдельном объекте (EntityState, если я правильно помню).

В моем собственном коде я разработал класс «DataMember», который не только сохранил значения, но также сохранил флаг изменения, нулевой статус и другие полезные вещи.Эти DataMembers были частными членами класса Entity, а Entity предоставили свойства, которые отображали данные как простые типы данных. Методы get и set свойств взаимодействовали с DataMember, чтобы «сделать правильную вещь», но DataMember выполнил отслеживание изменений. Класс My Entity, унаследованный от класса EntityBase, который предоставляет методы для проверки изменений на уровне сущности, принимает изменения (сбросить флажки изменений) и т. Д. Добавление уведомления об изменении будет следующим, что я делаю, но имея класс DataMember для отдельных элементы данных и EntityBase для управления обработчиком событий уведомления об изменениях, упростит это.

отредактирован ADD:

Теперь, когда я на работе, я могу добавить некоторые примеры кода. Вот определение интерфейса для моего класса DataMember:

public interface IDataMember<T> : IDataMember 
{ 
    T Value { get; set; } 

    T Get(); 

    void Set(T value); 
} 

public interface IDataMember 
{ 
    string FieldName { get; set; } 
    string OracleName { get; set; } 
    Type MemberType { get; } 
    bool HasValue { get; set; } 
    bool Changed { get; set; } 
    bool NotNull { get; set; } 
    bool PrimaryKey { get; set; } 
    bool AutoIdentity { get; set; } 
    EntityBase Entity { get; set;} 

    object GetObjectValue(); 

    void SetNull(); 
} 

Вот типичное свойство в классе сущностей:

private DataMember<bool> m_Monday; 

public bool? Monday 
{ 
    get 
    { 
     if (m_Monday.HasValue) 
      return m_Monday.Get(); 
     else 
      return null; 
    } 
    set 
    { 
     if (value.HasValue) 
      m_Monday.Set(value.Value); 
     else 
      m_Monday.SetNull(); 
    } 
} 

Обратите внимание, что DataMember может поддерживать свойства, как обнуляемые, или нет.

Конструктор код для добавления DataMember:

m_Monday = new DataMember<bool>("Monday"); 
    Members.Add(m_Monday); 
Смежные вопросы