2009-05-21 5 views
4

내 데이터 엔티티 인 클래스 목록을 직렬화하고 있습니다. List가 포함 된 DataProvider가 있습니다.C# - 목록 <T>이 더러운 지 확인 하시겠습니까?

나는 항상 컬렉션 내에서 직접 항목을 수정합니다.

목록에있는 항목이 변경되었는지 확인하는 가장 좋은 방법은 무엇입니까? Compact Framework를 사용하고 있습니다.

나의 현재의 생각은 목록을로드 할 때 (가능하다면) 목록의 해시를 만드는 것입니다. 그런 다음 저장을하면 목록의 해시를 다시 가져 와서 다른 값인지 확인합니다. 그들이 다른 경우 저장 한 후 비교를 위해 저장된 해시를 업데이트합니다. 동일하다면 저장하지 않습니다.

아이디어가 있으십니까?

+0

해시 건배 아이디어를 사용합니다 ... –

+0

어떻게 해싱 아이디어를 만들 수 있습니까? – GenericTypeTea

+0

목록에서 항목의 속성을 변경하면 목록이 변경되지 않는다는 점에 유의해야합니다. 나는 lassevk의 suggegstion과 함께 갈 것입니다. – Onots

답변

9

목록에 추가하는 항목이 INotifyPropertyChanged 인터페이스를 구현하는 경우 목록에 추가하는 모든 개체에 대해 해당 인터페이스에서 이벤트를 후크하고 항목이 제거 될 때 이벤트의 연결을 해제합니다 그 목록.

프레임 워크에 사용할 수있는 클래스가 BindingList<T>이거나 직접 작성할 수도 있습니다.

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를 지원하지 않습니다,하지만 그들은 여기

는 유형이 where T: INotifyPropertyChanged로 선언 된 가정, 샘플 추가 방법입니다 수업을 들으면, 나는 그 지원을 추가하는 것을 고려할 것이다.

+0

불과 1 년 후 ... 12 개월 전에 생각한 것보다 더 좋은 대답이라고 판단했습니다. – GenericTypeTea

4

IList<T> 클래스를 만들 수 있습니다 (예 : DirtyList<T>). 목록이 변경되면이를 기록 할 수 있습니다.

+0

어떻게 그 일을 할 수 있습니까? 나는이 아이디어를 가지고 있었고, 항목이 목록 안에서 바뀌 었는지, 즉 항목 [0] .Id = NewId()가 어떻게 바뀌 었는지를 알 수 없다는 사실 때문에 그것을 폐기했다. 항목이 변경된 것을 알고 있습니까? – GenericTypeTea

+3

편도 - 목록을 수정하는 (즉, 추가) 메소드와 부울을 재정 의하여 부울 플래그를 변경 한 다음 기본 메소드를 호출합니다. – annakata

+0

나는 그를 올바르게 이해하고 있다면, 그는 다음과 같은 일을합니다 : list [1] .Prop = newValue; 목록의 색인 1에있는 항목이 변경된 목록을 알리는 경우 (목록에 있음을 알리는 경우가 아니라면)이 명령문은 더티 플래그로 설정하지 않습니다.이 [index] get call을 더러움으로 –

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

불행히도 내 데이터 공급자 기본 클래스가 List 을 사용하고 List 가 아닌 것을 고려하면 그렇게 할 수 있다고 생각하지 않으므로 두 목록을 비교할 방법이 없습니다. – GenericTypeTea

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 구현에 존재한다는 보장은 없습니다.

+0

CF 버전 2.0에서이 작업을 수행하는 방법은 무엇입니까? 이것은 완벽 할 것입니다. – GenericTypeTea

+0

이 작업이 가능하지만 목록 에서 항목이 수정되면 증가하지 않습니다. – GenericTypeTea

1

T가 더티 플래그가있는 개체의 자손이고 IList 구현에 목록의 더티 플래그를 처리하는 개체가 있는지 확인하십시오.

2

어때?

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

*하세요 : 목록에 포함 된 모든 구성원에 대해 제대로 구현 (그리고 때 요소가 변경 변경)되어 GetHashCode() 나는의 라인을 따라 뭔가를 상상 거라고 가정

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

내가 여기에 타이핑을하고 컴파일러를 가지고 있지 않다는 것을 알아 두십시오. 그래서 위에 명시된 코드는 결코 작동하지 않을 것입니다. 그러나 잘하면이 아이디어를 보여줄 것입니다.