2009-05-21 19 views
4

我正在序列化作爲我的數據實體的類的列表。我有一個包含List的DataProvider。C# - 確定列表<T>是否髒?

我總是直接在集合中修改項目。

確定列表中的任何項目是否發生了變化的最佳方法是什麼?我正在使用Compact Framework。

我唯一的當前想法是在我加載列表時創建列表的散列(如果可能的話)。然後當我進行保存時,我重新獲得列表的哈希值,並查看它們是否是不同的值。如果它們不同,我保存,然後更新存儲的哈希以便稍後進行比較,如果它們相同,則不保存。

任何想法?

+0

我會用哈希thingy的想法... – 2009-05-21 09:15:57

+0

我怎麼做我的哈希想法? – GenericTypeTea 2009-05-21 09:23:04

+0

您必須記住,當您更改列表中項目的屬性時,列表不會更改。我會用lassevk的suggegstion去。 – Onots 2009-05-21 12:21:18

回答

9

如果您添加到列表中的項目實施INotifyPropertyChanged界面,你可以建立掛接在該接口爲您添加到列表中的所有對象的事件,脫鉤當項目從刪除的情況下自己的泛型列表列表。

在框架中有一個BindingList<T>類可以使用,或者你可以自己寫。

下面是一個示例add方法,假設類型已被宣佈與where T: INotifyPropertyChanged

public void Add(T item) 
{ 
    // null-check omitted for simplicity 
    item.PropertyChanged += ItemPropertyChanged; 
    _List.Add(item); 
} 

this[index]索引屬性:

public T this[Int32 index] 
{ 
    get { return _List[index]; } 
    set { 
     T oldItem = _List[index]; 
     _List[index] = value; 
     if (oldItem != value) 
     { 
      if (oldItem != null) 
       oldItem.PropertyChanged -= ItemPropertyChanged; 
      if (value != null) 
       value.PropertyChanged += ItemPropertyChanged; 
     } 
    } 
} 

如果您的項目不支持INotifyPropertyChanged,但他們'你的課程,我會考慮增加支持。

4

您可以創建屬於自己的IList<T>類,比如DirtyList<T>,它可以記錄列表何時更改。

+0

我該怎麼做呢?我有這個想法,並廢除它,因爲我不知道如何確定項目是否在列表中更改,即項目[0] .Id = NewId(),我的列表如何知道該項目已經改變? – GenericTypeTea 2009-05-21 09:26:21

1

你可以實現你自己的列表,維護2個內部列表......以及實例化版本和跟蹤版本......例如,

//Rough Psuedo Code 
public class TrackedList<T> : List<T> 
{ 
    public bool StartTracking {get; set; } 
    private List<T> InitialList { get; set; } 

    CTOR 
    { 
     //Instantiate Both Lists... 
    } 

    ADD(item) 
    { 
     if(!StartTracking) 
     { 
      Base.Add(item); 
      InitialList.Add(item); 
     } 
     else 
     { 
      Base.Add(item); 
     } 
    } 

    public bool IsDirty 
    { 
     get 
     { 
      Check if theres any differences between initial list and self. 
     } 
    } 
} 
4

如果你願意使用反射,在List<T>類有一個名爲_version私有字段遞增每次名單的變化。它不會告訴您哪些項目已更改,但您可以將其與原始值_version進行比較以檢測未修改的列表。

作爲參考,此字段用於確保枚舉器在列表被修改時變爲無效。因此,除非List<T>的實際託管代碼發生更改,否則您應該能夠將其用於相當可靠的目的。

要獲得_version的價值,你可以使用這樣的事情:

List<T> myList; 
var field = myList.GetType().GetField("_version", BindingFlags.Instance | BindingFlags.NonPublic); 
int version = field.GetValue(myList); 

一般來說,雖然,這是不是最好的方法。如果你被其他人創建的List<T>卡住了,但是,它可能是你擁有的最佳選擇。請注意,對.NET框架所作的更改可能會更改該字段的名稱(或將其完全移除),並且不能保證存在於像Mono這樣的第三方CLR實現中。

1

確保T是具有髒標誌的對象的後代,並且IList實現檢查是否涉及列表的髒標誌。

2

這樣的事情呢?

public class ItemChangedArgs<T> : EventArgs 
{ 
    public int Index { get; set; } 
    public T Item { get; set; } 
} 

public class EventList<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable 
{ 
    private List<T> m_list; 
    public event EventHandler<ItemChangedArgs<T>> ItemAdded; 
    public event EventHandler<ItemChangedArgs<T>> ItemRemoved; 
    public event EventHandler<ItemChangedArgs<T>> ItemChanged; 
    public event EventHandler ListCleared; 

    public EventList(IEnumerable<T> collection) 
    { 
     m_list = new List<T>(collection); 
    } 

    public EventList(int capacity) 
    { 
     m_list = new List<T>(capacity); 
    } 

    public EventList() 
    { 
     m_list = new List<T>(); 
    } 

    public void Add(T item) 
    { 
     Add(item, true); 
    } 

    public void Add(T item, Boolean raiseEvent) 
    { 
     m_list.Add(item); 
     if (raiseEvent) RaiseItemAdded(this.Count - 1, item); 
    } 

    public void AddRange(IEnumerable<T> collection) 
    { 
     foreach (T t in collection) 
     { 
      m_list.Add(t); 
     } 
    } 

    private void RaiseItemAdded(int index, T item) 
    { 
     if (ItemAdded == null) return; 

     ItemAdded(this, new ItemChangedArgs<T> { Index = index, Item = item }); 
    } 

    public int IndexOf(T item) 
    { 
     return m_list.IndexOf(item); 
    } 

    public void Insert(int index, T item) 
    { 
     m_list.Insert(index, item); 
     RaiseItemAdded(index, item); 
    } 

    public void RemoveAt(int index) 
    { 
     T item = m_list[index]; 
     m_list.RemoveAt(index); 
     RaiseItemRemoved(index, item); 
    } 

    private void RaiseItemRemoved(int index, T item) 
    { 
     if(ItemRemoved == null) return; 
     ItemRemoved(this, new ItemChangedArgs<T> { Index = index, Item = item }); 
    } 

    public T this[int index] 
    { 
     get { return m_list[index]; } 
     set 
     { 
      m_list[index] = value; 
      RaiseItemChanged(index, m_list[index]); 
     } 
    } 

    private void RaiseItemChanged(int index, T item) 
    { 
     if(ItemChanged == null) return; 
     ItemChanged(this, new ItemChangedArgs<T> { Index = index, Item = item }); 
    } 

    public void Clear() 
    { 
     m_list.Clear(); 
     RaiseListCleared(); 
    } 

    private void RaiseListCleared() 
    { 
     if(ListCleared == null) return; 
     ListCleared(this, null); 
    } 

    public bool Contains(T item) 
    { 
     return m_list.Contains(item); 
    } 

    public void CopyTo(T[] array, int arrayIndex) 
    { 
     m_list.CopyTo(array, arrayIndex); 
    } 

    public int Count 
    { 
     get { return m_list.Count; } 
    } 

    public bool IsReadOnly 
    { 
     get { return false; } 
    } 

    public bool Remove(T item) 
    { 
     for (int i = 0; i < m_list.Count; i++) 
     { 
      if(item.Equals(m_list[i])) 
      { 
       T value = m_list[i]; 
       m_list.RemoveAt(i); 
       RaiseItemRemoved(i, value); 
       return true; 
      } 
     } 
     return false; 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     return m_list.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return m_list.GetEnumerator(); 
    } 
} 
2

假設GetHashCode()方法對列表中包含的每一個成員正確實施(從而改變當一個元素的變化)我的線沿線的想象的東西:

public class DirtyList<T> : List<T> { 
    private IList<int> hashCodes = new List<int> hashCodes(); 
    public DirtyList() : base() { } 
    public DirtyList(IEnumerable<T> items) : base() { 
     foreach(T item in items){ 
      this.Add(item); //Add it to the collection 
      hashCodes.Add(item.GetHashCode()); 
     } 
    } 

    public override void Add(T item){ 
     base.Add(item); 
     hashCodes.Add(item); 
    } 
    //Add more logic for the setter and also handle the case where items are removed and indexes change and etc, also what happens in case of null values? 

    public bool IsDirty { 
     get { 
      for(int i = 0; i < Count: i++){ 
       if(hashCodes[i] != this[i].GetHashCode()){ return true; } 
      } 
      return false; 
     } 
    } 
} 

*請請注意我在SO上鍵入了這些內容,並且沒有編譯器,因此上述代碼絕不是工作的保證,但希望它能顯示出這個想法。