如何检查对象是否已更改?
我有一个对象,其中包含其他对象,其中包含其他对象,包括列表等。 此对象数据绑定到表单,在不同选项卡中向用户公开许多字段。 我还使用了master-child datagridviews。
任何想法如何检查此对象中是否有任何相对于早期时刻发生了变化? 不(手动)添加已更改的变量,在所有(> 100)设置方法中设置为true。
你如何定义“平等”(新旧状态之间)?
- 您是仅比较属性还是字段?
- 你只是比较公共财产/领域吗?
- 你有没有忽略任何属性/领域(即他们的修改无关紧要)?
- 您如何比较“primefaces”类型(例如,所有字符串比较都不区分大小写,或者您在某些地方也需要区分大小写)。
如果这些问题的答案足够普遍(即你可以设计一套适用于所有对象的规则),那么理论上你可以通过反思完成你想要的东西:基本思想是阅读“所有属性/字段” root“对象,然后存储”primefaces“对象并递归地下降到”非primefaces“对象(并重复整个过程)。 稍后,当您想要检查是否有任何更改时,您将重复递归下降并将结果与存储的值进行比较。
我并不认为这个解决方案特别高效甚至容易(你需要设计一个强大的命名约定来存储旧值并且非常注意multithreading),但它可能是一般性的。
正如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 children_ = new List (); public bool IsDirty { get { bool ret = dirty_; foreach (IDirty child in children_) dirty_ |= child.IsDirty; return ret; } } } // eo class SomeObjectWithChildren
您可以实现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
您可以覆盖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的博客后 ,
我同意不得使用GetHashCode。
我保留了答案以保持丰富的讨论。
随着时间的推移比较哈希码可能是一种选择。 如果您不想添加该逻辑,则可以将对象序列化两次,并比较两个结果字符串的哈希码。
编辑包含一些注释看看这个问题/答案: 可以序列化同一个对象产生不同的流吗?
因此请注意一个串行器,它不会**保证同一对象的相同输出两次。
我可以采取这样的事情:
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)); } } } }
希望能帮助到你