我需要知道如何检查对象是否已更改。基本上我需要类似于名为TrackChanges的属性,当我将其设置为true一次并且如果此对象中的任何数据被“更改”时,同一对象上的方法(IsObjectChanged)可以返回true。
你有没有需要这样的东西,你是如何解决的?如果已经有这种情况的最佳实践,我不想发明轮子?
我想在我的setter中调用TrackChange = true之前克隆该对象。当我调用IsObjectChanged()时,通过使用反射,我将比较它的所有公共字段值和克隆的副本。我不确定这是不是一个好方法。
有任何建议吗?
感谢, burak ozdogan
答案 0 :(得分:16)
当我需要跟踪对象的属性更改以进行测试时,我在对象PropertyChanged事件上挂钩了一个事件处理程序。这对你有帮助吗?然后,您的测试可以根据更改执行他们想要的任何操作。通常我会计算更改次数,并将更改添加到词典等。
要实现此目的,您的课程必须实现INotifyPropertyChanged界面。然后任何人都可以附加和收听已更改的属性:
public class MyClass : INotifyPropertyChanged { ... }
[TestFixture]
public class MyTestClass
{
private readonly Dictionary<string, int> _propertiesChanged = new Dictionary<string, int>();
private int _eventCounter;
[Test]
public void SomeTest()
{
// First attach to the object
var myObj = new MyClass();
myObj.PropertyChanged += SomeCustomEventHandler;
myObj.DoSomething();
// And here you can check whether the object updated properties - and which -
// dependent on what you do in SomeCustomEventHandler.
// E.g. that there are 2 changes - properties Id and Name changed once each:
Assert.AreEqual(2, _eventCounter);
Assert.AreEqual(1, _propertiesChanged["Id"]);
Assert.AreEqual(1, _propertiesChanged["Name"]);
}
// In this example - counting total number of changes - and count pr property.
// Do whatever suits you.
private void SomeCustomEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
var property = e.PropertyName;
if (_propertiesChanged.ContainsKey(property))
_propertiesChanged[property]++;
else
_propertiesChanged[property] = 1;
_eventCounter++;
}
}
答案 1 :(得分:4)
这有两个部分。变更通知的事件是一个部分,但保持历史是另一个重要的部分。实体框架也是这样做的(就像LINQ to SQL一样),我也在自己的代码中实现了这一点。至少,您为成员保留一个标志,表明它已更改。根据您的要求,您也可以保留原始值。这通常成为单独对象的任务。实体框架将其更改跟踪保存在单独的对象中(如果我没记错的话,实体状态)。
在我自己的代码中,我开发了一个“DataMember”类,它不仅保存了值,还保留了更改标志,空状态和各种其他有用的东西。这些DataMembers是Entity类中的私有成员,Entity提供了将数据公开为简单数据类型的属性。属性get和set方法与DataMember交互以“做正确的事”,但DataMember确实改变了跟踪。我的Entity类继承自“EntityBase”类,它提供了在实体级别检查更改的方法,接受更改(重置更改标志)等。添加更改通知将是我接下来要做的事情,但是为个人提供DataMember类数据元素和拥有更改通知事件处理程序的EntityBase将简化这一过程。
编辑添加:
现在我正在工作,我可以添加一些代码示例。这是我的DataMember类的接口定义:
public interface IDataMember<T> : IDataMember
{
T Value { get; set; }
T Get();
void Set(T value);
}
public interface IDataMember
{
string FieldName { get; set; }
string OracleName { get; set; }
Type MemberType { get; }
bool HasValue { get; set; }
bool Changed { get; set; }
bool NotNull { get; set; }
bool PrimaryKey { get; set; }
bool AutoIdentity { get; set; }
EntityBase Entity { get; set;}
object GetObjectValue();
void SetNull();
}
这是实体类中的典型属性:
private DataMember<bool> m_Monday;
public bool? Monday
{
get
{
if (m_Monday.HasValue)
return m_Monday.Get();
else
return null;
}
set
{
if (value.HasValue)
m_Monday.Set(value.Value);
else
m_Monday.SetNull();
}
}
请注意,DataMember可以支持属性为可空或无。
添加DataMember的构造函数代码:
m_Monday = new DataMember<bool>("Monday");
Members.Add(m_Monday);
答案 2 :(得分:3)
布拉克,
您可以查看实体框架或Microsoft的其他框架。 您可以看到PropertyChanging或PropertyChanged等事件。
查看生成的代码。
您也可以查看NHibernate代码,但由于代码库非常庞大,因此最好查看Microsoft ORM生成器。
答案 3 :(得分:2)
实施并使用界面INotifyPropertyChanged。没有字符串文字的一种很酷的方法是here。
答案 4 :(得分:1)
为什么不创建List并将第一个对象放入,然后可以通过简单比较将其与当前对象进行比较。
如上所述,您可以使用INotifyPropertyChanged查看对象中已更改的属性。
答案 5 :(得分:0)
您应该创建一个事件,并将其称为OnChanged
。