Подтвердить что ты не робот

Какова наилучшая практика для проверки того, изменился ли объект?

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

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

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

Любые советы?

спасибо, burak ozdogan

4b9b3361

Ответ 1

Когда мне нужно отслеживать изменения свойств на моих объектах для тестирования, я подключаю обработчик событий к объекту события 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++;
    }
}

Ответ 2

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

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

ИЗМЕНИТЬ ДОБАВИТЬ:

Теперь, когда я нахожусь на работе, я могу добавить примеры кода. Здесь определение интерфейса для моего класса 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);

Ответ 3

Бурак,

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

Взгляните на сгенерированный код.

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

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