2010-01-15 150 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); 
相關問題