Как проверить, изменился ли объект?

17

У меня есть объект, который содержит другие объекты, которые содержат другие объекты, включая списки и т. д. Этот объект привязывается к форме, привязывая многочисленные поля к пользователю на разных вкладках. Я также использую master-child datagridviews.

Любая идея, как проверить, изменилось ли что-нибудь в этом объекте относительно более раннего момента? Без (вручную) добавления измененной переменной, для которой установлено значение true во всех методах (& gt; 100).

    
задан willem 31.10.2011 в 11:44
источник
  • Просто любопытно, но зачем вам это нужно. Если ваш объект правильно привязан к базе данных, форма должна обновляться соответствующим образом. –  Bas Slagter 31.10.2011 в 11:46
  • Что здесь означают объекты. Вы имеете в виду разные компоненты или объекты, объявленные вами из разных типов? Это немного запутанно. –  Rahul 31.10.2011 в 11:47
  • Что значит «Без (вручную) добавления измененной переменной« Вы не хотите писать код, чтобы решить эту проблему? –  Ritch Melton 31.10.2011 в 11:49
  • Объекты могут быть простыми, такими как удвоения или строки, но также списки пользовательских объектов, которые могут содержать списки других объектов. –  willem 31.10.2011 в 11:49
  • Существует множество способов реализации грязного флага. stackoverflow.com/questions/553882/... –  Ritch Melton 31.10.2011 в 11:53
Показать остальные комментарии

6 ответов

3

Как вы определяете «равенство» (между старым и новым состоянием)?

  • Вы сравниваете только свойства или поля?
  • Вы сравниваете только общедоступные свойства / поля?
  • Вы когда-либо игнорировали любые свойства / поля (т. е. их модификации не имеют значения)?
  • Как вы сравниваете «атомные» типы (например, все строковые сравнения не учитывают регистр, или вам также необходимо учитывать регистр в некоторых местах).

Если ответы на эти вопросы достаточно общие (т. е. вы можете разработать набор правил, применимых ко всем вашим объектам), то вы теоретически можете выполнить то, что хотите, через отражение : основная идея - читать все свойства / поля «корневого» объекта, затем хранить «атомные» и рекурсивно спускаться в «неатомные» (и повторять весь процесс). Позже, когда вы хотите проверить, что-то изменилось, вы повторите рекурсивный спуск и сравните результаты с сохраненными значениями.

Я не утверждаю, что это решение особенно результативно или даже просто (вам нужно разработать надежное соглашение об именах для хранения старых значений и быть очень осторожным в многопоточности), но это потенциально может быть общим .

    
ответ дан Branko Dimitrijevic 31.10.2011 в 12:41
  • Мне нравится идея отражения, но я бы предпочел не реализовывать ее сам. Могу ли я уговорить XML-сериализатор проверить равенство? Или это переупорядочивает вещи? –  willem 31.10.2011 в 14:04
7

Как сказано в Sll, грязный интерфейс, безусловно, хороший способ. Принимая это дальше, мы хотим, чтобы коллекции были грязными, но мы не хотим, чтобы ВСЕ дочерние объекты устанавливались как грязные. Однако мы можем объединить результаты их грязного состояния с нашим собственным грязным состоянием. Поскольку мы используем интерфейсы, мы оставляем их для объектов, чтобы определить, загрязнены они или нет.

Мое решение не скажет вам, что что является грязным, просто загрязнение состояния любого объекта в любой момент.

public interface IDirty
{
    bool IsDirty { get; }
}   // eo interface IDirty


public class SomeObject : IDirty
{
    private string name_;
    private bool dirty_;

    public string Name
    {
        get { return name_; }
        set { name_ = value; dirty_ = true; }
    }
    public bool IsDirty { get { return dirty_; } }
}   // eo class SomeObject


public class SomeObjectWithChildren : IDirty
{
    private int averageGrades_;
    private bool dirty_;
    private List<IDirty> children_ = new List<IDirty>();

    public bool IsDirty
    {
        get
        {
            bool ret = dirty_;
            foreach (IDirty child in children_)
                dirty_ |= child.IsDirty;
            return ret;
        }
    }

}   // eo class SomeObjectWithChildren
    
ответ дан Moo-Juice 31.10.2011 в 12:52
  • Мне нравится, как вы это предложили, но я, вероятно, упустил бы строку Event на SetChange в Access Accessors. –  Burimi 31.10.2011 в 15:16
4

Вы можете реализовать интерфейс INotifyPropertyChanged, и если у пользователя VS2010 есть addin, который автоматически изменяет все свойства в IL (поэтому вам не нужно выполнять его вручную).

Я верю, что есть и другие методы, которые используют технику ткачества.

Я нашел addin в галерее vs2010:

Ссылка

Есть хороший пример - ваш код:

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string GivenNames { get; set; }
}

Что скомпилировано:

public class Person : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    private string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }
}

Это первая ссылка из unce G (может быть полезно):

Ссылка

Ссылка

    
ответ дан Kamil Lach 31.10.2011 в 11:52
  • Я лично не буду использовать INotifyPropertyChanged (pub / sub) при прохождении родительского графа, поскольку походка родителя по требованию, и может быть перенесена в параллельную или фоновую задачу. Модели событий, как правило, приводят к бурям событий в крупных приложениях, и многие из них развивают их. –  Ritch Melton 31.10.2011 в 12:27
0

Вы можете переопределить GetHashCode , а затем создать хэш-код, который представляет собой смесь свойств объекта. Итак, ваша программа получит хэш-код объекта, сохранит его, а затем на следующей проверке, сравните его с текущим хэш-кодом.

Очень упрощенный подход :

internal class Foo
{
    public string Bar { get; set; }
    public int Baaz { get; set; }

    public override int GetHashCode()
    {
        return Bar.GetHashCode() - Baaz.GetHashCode();
    }
}

Будьте осторожны , так как вам нужно искать Bar , не являющуюся null , а также обслуживать переполнение целых чисел .

ИЗМЕНИТЬ

Посмотрев на блог ,

Я согласен, что GetHashCode не должен использоваться.

Я держу ответ, чтобы сохранить массу обсуждений.

    
ответ дан Aliostad 31.10.2011 в 11:47
  • ^ это должно быть предостерегаемо с предупреждением, которое идет с реализованным хэш-кодом, который изменяется. Было бы так же легко добавить флаг IsDirty. –  Ritch Melton 31.10.2011 в 11:51
  • Нет, это не так. IsDirty должен быть установлен на всех сеттерах свойств класса и всех классов, используемых в этом классе. Urrrgh, .. А потом, когда вы его сбросите? Предположим, он изменен, и вы хотите узнать, изменилось ли оно снова? –  Aliostad 31.10.2011 в 11:53
  • Правильно, это требует определенных усилий и может потребовать немного инфраструктуры (если ваши требования диктуют это), но он работает без использования GetHashCode таким образом, что он перегружает (и, возможно, прерывает) его предполагаемое использование. –  Ritch Melton 31.10.2011 в 12:00
  • Использование хеш-кода для этого не является хорошей идеей. Прежде всего, вам придется переопределить метод Equals (). Во-вторых, хэш объекта никогда не должен меняться в течение жизни объекта (также подразумевается, что он должен быть неизменным там, где это важно). Вы используете существующий метод по неправильным причинам, просто чтобы сохранить одну запись отдельной. –  Jeff Mercado 31.10.2011 в 12:01
  • @Aliostad - stackoverflow.com/questions/462451/... –  Ritch Melton 31.10.2011 в 12:17
Показать остальные комментарии
0

Сравнение кодов Хэша со временем может быть опцией. Если вы не хотите добавлять эту логику, вы можете дважды сериализовать объект и сравнить хэш-коды двух результирующих строк.

ИЗМЕНИТЬ, чтобы включить некоторые комментарии Посмотрите на этот вопрос / ответ: Может ли сериализация одного и того же объекта производить разные потоков?

Так что знайте о сериализаторе, который ** не ** гарантирует одинаковый вывод для одного и того же объекта дважды.

    
ответ дан Erno de Weerd 31.10.2011 в 11:51
  • Сериализованный поток двух объектов с точно такими же значениями не гарантируется одинаковым. Я видел это своими глазами. –  Aliostad 31.10.2011 в 12:07
  • Мне нравится идея сериализации, но не хэш-код. –  Ritch Melton 31.10.2011 в 12:08
  • @ Не обращайте внимания на хэш-код, потоки не гарантируются одинаковыми. –  Aliostad 31.10.2011 в 12:11
  • Я думаю, это зависит от типа сериализации. Речь идет не о том, что потоки равны, а о форматировании, создающем ту же «вещь» / структуру / строку –  Erno de Weerd 31.10.2011 в 12:15
  • @При этом вы идете с prooooof stackoverflow.com/questions/7954275/... –  Aliostad 31.10.2011 в 14:46
Показать остальные комментарии
0

Я могу сказать что-то вроде этого:

public class ObjectBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(propertyName, true);
        }

        protected virtual void OnPropertyChanged(string propertyName, bool makeDirty)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            if (makeDirty)
                _IsDirty = true;
        }


        bool _IsDirty;

        public bool IsDirty
        {
            get { return _IsDirty; }
        }

    }

, то в свойстве свойства вы можете

public class Vehicle : ObjectBase
{


  int _CarId;

 public int CarId
        {
            get { return _CarId; }
            set
            {
                if (_CarId != value)
                {
                    _CarId = value;
                    OnPropertyChanged(nameof(CarId));
                }

            }
        }
  }

надеюсь, что это поможет

    
ответ дан Carlos Abreu 26.05.2016 в 02:28
  • Не знаете, как это будет работать. Как узнать, действительно ли свойство загрязнено (изменено), кроме свойства, которое было просто установлено при создании экземпляра? –  don_mega 13.09.2017 в 18:30