如何检查对象是否已更改?

时间:2011-10-31 10:44:14

标签: c#

我有一个对象,其中包含其他对象,其中包含其他对象,包括列表等。此对象是数据绑定到表单,在不同的选项卡中向用户公开了许多字段。 我还使用了master-child datagridviews。

任何想法如何检查此对象中是否有任何相对于较早时刻的变化?没有(手动)添加已更改的变量,在所有(> 100)设置方法中设置为true。

7 个答案:

答案 0 :(得分:8)

正如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

答案 1 :(得分:4)

您可以实现INotifyPropertyChanged接口,如果您使用VS2010,则会自动更改IL中的所有属性(因此您不必手动实现)。

我相信还有其他一些使用编织技术的方法。

我在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");
            }
        }
    }
}

这是从第一次来自G(可能有用):

http://justinangel.net/AutomagicallyImplementingINotifyPropertyChanged

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

答案 2 :(得分:3)

如何定义“平等”(新旧状态之间)?

  • 您是仅比较属性还是字段?
  • 您只是在比较公开属性/字段吗?
  • 您是否忽略任何属性/字段(即其修改无关紧要)?
  • 如何比较“原子”类型(例如,所有字符串比较都不区分大小写,或者在某些地方也需要区分大小写)。

如果这些问题的答案足够普遍(即你可以设计一套适用于所有物体的规则),那么理论上你可以通过反思完成你想要的:基本理念是读取“根”对象的所有属性/字段,然后存储“原子”对象并递归地下降到“非原子”对象(并重复整个过程)。稍后,当您想要检查是否有任何更改时,您将重复递归下降并将结果与​​存储的值进行比较。

我并不认为这个解决方案特别高效甚至容易(您需要设计一个强大的命名约定来存储旧值并且非常注意多线程),但它可能是一般的

答案 3 :(得分: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并且还要满足整数溢出。


修改

看了Eirc Lippert的blog

我同意不得使用GetHashCode。

我保留了答案以保持丰富的讨论。

答案 4 :(得分:0)

随着时间的推移比较哈希码可能是一种选择。如果您不想添加该逻辑,可以将对象序列化两次,并比较两个结果字符串的哈希码。

编辑以包含一些评论 看看这个问题/答案:Can serializing the same object produce different streams?

所以要注意一个串行器,它不会**保证同一个对象的输出相同两次。

答案 5 :(得分: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));
                }

            }
        }
  }

希望有所帮助

答案 6 :(得分:0)

如果您想要轻松,轻松地执行此操作,那么@Burimi是正确的,因为您需要在类设置器和getter中进行管理。

您将不得不原谅表达式,但是,“老派”将您的类/对象属性“变回”为具有公共私有获取器和私有访问器的访问器。在公共设置器中,您将在其中设置对象的脏标志以及私有变量...但是您必须对每个重要的属性进行逐一设置...我个人认为这是其中之一将来:

public string FirstName { get; set => { this.isDirty=true; } }

基本上等同于当前的{ get; set; },但是,如果其中任何一个旁边都有=>,则等同于and run this code at after //getting or setting it,但我不知道甚至不知道这是当今人们想要的东西。

public class myObject
{
    public bool isDirty { get; set; }
    private string FirstName_ = "";
    public string FirstName { get { return FirstName_; } set { FirstName_ = value; isDirty = true; } }
}

现在,只要更改FirstName_,整个对象都会变脏……重复冲洗。

当然,如果您还想报告该事件,那么您要做的就是触发一个通知事件,该事件创建了您自己并拥有所需的数据...这是我的意思的示例:

public class myObject
{
    public bool isDirty { get; set; }
    private string FirstName_ = "";
    public string FirstName { get { return FirstName_; } set { FirstName_ = value; isDirty = true; RaisePropertyChanged("FirstName"); } }

    #region use YOUR_OWN_NOTIFY_EventHandler

    public event YOUR_OWN_NOTIFY_EventHandler PropertyChanged;

    public void RaisePropertyChanged(string propertyName)
    {
        YOUR_OWN_NOTIFY_EventTHandler handler = PropertyChanged;
        if (handler != null) handler(new myPropertyChangedEventArgs(propertyName));
    }

    #endregion
}

希望这对某人有帮助...