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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

Как сказано в 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

Ответ 3

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

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

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

http://visualstudiogallery.msdn.microsoft.com/bd351303-db8c-4771-9b22-5e51524fccd3

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

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 (может быть полезно):

http://justinangel.net/AutomagicallyImplementingINotifyPropertyChanged

http://www.codeproject.com/KB/WPF/AutonotifyPropertyChange.aspx

Ответ 4

Вы можете переопределить 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, а также обслуживать переполнение целых чисел .


ИЗМЕНИТЬ

Посмотрев на Eirc Lippert blog,

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

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

Ответ 5

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

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

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

Ответ 6

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

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));
                }

            }
        }
  }

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

Ответ 7

У меня та же проблема. я не хочу менять свойства набора классов. Проектирование класса будет для меня массовой работой. должен быть простой способ выглядеть так: myObj.ismodified == true