2010-01-15 153 views
23

我需要知道你如何检查一个对象是否被改变。基本上我需要一个名为TrackChanges的属性,当我将它设置为true时,如果此对象中的任何数据“已更改”,则同一对象上的方法(IsObjectChanged)可以返回true。检查对象是否被更改的最佳做法是什么?

你是否曾经需要过这样的事情,你是如何解决它的?如果已经有这种情况的最佳做法,我不想发明轮子?

我打算在我调用TrackChange = true之前在其setter中克隆对象。当我调用IsObjectChanged()通过使用反射,我会比较它的所有公共字段值与克隆副本。我不确定这是否是一种好方法。

任何建议?

感谢, 布拉克ozdogan

+0

可能重复【什么是说,如果一个对象被修改的最佳方法?(http://stackoverflow.com/questions/34809/what-是最好的方式来告诉,如果一个对象被修改) – mathieu 2012-08-16 12:29:04

回答

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++; 
    } 
} 
+0

好! Bur问题: 1)什么被认为是“改变?” msdn中说它在调用setter时被抛出。所以我仍然需要检查它是否与前面的值不同,对吗? 2)如果这个对象的属性是对另一种类型对象的引用,如果该对象的属性发生了变化,我认为案例变得复杂得多。如: myPerson.Address.Ctiy =“aDifferentCityName” – pencilCake 2010-01-15 12:59:46

+0

更改是一个PropertyChanged事件。实现INotifyPropertyChanged接口,你需要自己触发事件。当你自己控制这个时,你基本上可以选择是否想要改变相同的值来作为改变。我不。 – stiank81 2010-01-15 13:03:21

+0

如果MyObject具有引用另一个对象的属性,并且在更改此对象时需要PropetyChanged事件,则MyObject需要在其引用的对象上挂接PropertyChanged事件并触发更改的事件以将其传递。它肯定会变得更加复杂 - 起初可能很难,但当你理解它时并不那么复杂。祝你好运! – stiank81 2010-01-15 13:06:01

3

布拉克,

你可以看一看实体框架或微软的其他框架。 您可以看到像PropertyChanging或PropertyChanged这样的事件。

看看生成的代码。

你可以看看NHibernate的代码为好,但由于该代码库是如此巨大,不如看看微软ORM发电机..

0

而不是创建一个属性,你应该创建一个事件并称之为OnChanged

1

为什么不创建一个List并放入第一个对象,然后通过使用简单的比较就可以将它与当前对象进行比较。

如上所述,您可以使用INotifyPropertyChanged来查看对象中已更改的属性。

+1

简单的比较将需要创建对象的(深层)副本。这在内存和时间上都很昂贵。 – 2010-01-15 13:01:53

4

这有两个部分。变更通知事件是一件事,但保持历史是另一件重要的事情。实体框架也是这样做的(就像LINQ to SQL一样),我也在自己的代码中实现了这一点。至少,你保持一个成员的标志,说它已经改变了。根据您的要求,您也可以保留原始值。这通常成为单独对象的任务。实体框架将其更改跟踪保存在单独的对象中(如果我没有记错的话,EntityState)。

在我自己的代码中,我开发了一个“DataMember”类,它不仅保存了值,还保存了更改标记,空状态以及其他各种有用的东西。这些DataMembers是实体类中的私有成员,并且实体提供了将数据作为简单数据类型公开的属性。属性get和set方法与DataMember交互以“做正确的事情”,但DataMember确实改变了跟踪。 My Entity类继承自“EntityBase”类,该类提供了在实体级别检查更改的方法,接受更改(重置更改标志)等。添加更改通知将是我所做的下一件事,但具有用于个人的DataMember类数据元素和一个EntityBase来拥有更改通知事件处理程序,这将简化很多。

编辑补充:

现在,我在工作,我可以添加一些代码样本。下面是我的数据成员的类接口定义:

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

注意,数据成员可以支持性能可为空,或者不是。

构造函数代码添加一个数据成员:的

m_Monday = new DataMember<bool>("Monday"); 
    Members.Add(m_Monday); 
相关问题