我有一个对象,其中包含其他对象,其中包含其他对象,包括列表等。此对象是数据绑定到表单,在不同的选项卡中向用户公开了许多字段。 我还使用了master-child datagridviews。
任何想法如何检查此对象中是否有任何相对于较早时刻的变化?没有(手动)添加已更改的变量,在所有(> 100)设置方法中设置为true。
答案 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,
我保留了答案以保持丰富的讨论。
答案 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
}
希望这对某人有帮助...