C# - 确定 List是否为 是脏的?

发布于 2024-07-20 02:51:27 字数 266 浏览 8 评论 0原文

我正在序列化作为我的数据实体的类列表。 我有一个包含列表的 DataProvider。

我总是直接修改集合中的项目。

确定列表中的任何项目是否已更改的最佳方法是什么? 我正在使用紧凑框架。

我当前唯一的想法是在加载列表时创建列表的哈希(如果可能的话)。 然后,当我进行保存时,我重新获取列表的哈希值并查看它们是否是不同的值。 如果它们不同,我保存,然后更新存储的哈希以供稍后比较,如果它们相同,则我不保存。

有任何想法吗?

I am serializing Lists of classes which are my data entities. I have a DataProvider that contains a List.

I always modify items directly within the collection.

What is the best way of determining if any items in the List have changed? I am using the Compact Framework.

My only current idea is to create a hash of the List (if that's possible) when I load the list. Then when I do a save I re-get the hash of the list and see if they're different values. If they're different I save and then update the stored Hash for comparison later, if they're the same then I don't save.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

绿光 2024-07-27 02:51:27

如果添加到列表中的项目实现 INotifyPropertyChanged< /code>接口,您可以构建自己的通用列表,为添加到列表中的所有对象在该接口中挂钩事件,并在从列表中删除项目时取消挂钩事件。

有一个 BindingList类您可以使用的框架,或者您可以编写自己的框架。

下面是一个示例添加方法,假设类型已使用 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,但它们是您的类,我会考虑添加该支持。

If the items you add to the list implement the INotifyPropertyChanged interface, you could build your own generic list that hooks the event in that interface for all objects you add to the list, and unhooks the event when the items are removed from the list.

There's a BindingList<T> class in the framework you can use, or you can write your own.

Here's a sample add method, assuming the type has been declared with where T: INotifyPropertyChanged:

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

and the this[index] indexer property:

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

If your items doesn't support INotifyPropertyChanged, but they're your classes, I would consider adding that support.

梦回旧景 2024-07-27 02:51:27

您可以创建自己的 IList 类,例如 DirtyList ,它可以记录列表何时发生更改。

You could create your own IList<T> class, say DirtyList<T> that can record when the list has changed.

怎言笑 2024-07-27 02:51:27

如果您愿意使用反射,List 类有一个名为 _version 的私有字段,每次列表更改时该字段都会递增。 它不会告诉您哪些项目已更改,但您可以将其与 _version 的原始值进行比较,以检测未修改的列表。

作为参考,该字段用于确保列表修改时枚举器变得无效。 因此,您应该能够相当可靠地使用它来达到您的目的,除非 List 的实际托管代码发生变化。

要获取 _version 的值,您可以使用如下所示的方法:

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

但一般来说,这不是最好的方法。 但是,如果您无法使用其他人创建的 List,那么这可能是您拥有的最佳选择。 请注意,对 .NET 框架的更改可能会更改字段的名称(或完全删除它),并且不保证它存在于 Mono 等第三方 CLR 实现中。

If you're willing to use reflection, the List<T> class has a private field called _version that is incremented every time the list changes. It won't tell you which items have changed, but you can compare it with the original value of _version to detect an unmodified list.

For reference, this field is used to ensure that enumerators become invalid when the list is modified. So you should be able to use it for your purposes fairly reliably, unless the actual managed code for List<T> changes.

To get the value of _version you can use something like this:

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

Generally speaking, though, this isn't the best approach. If you're stuck using a List<T> that someone else created, however, it's probably the best option you have. Please be aware that changes to the .NET framework could change the name of the field (or remove it entirely), and it's not guaranteed to exist in third-party CLR implementations like Mono.

薯片软お妹 2024-07-27 02:51:27

像这样的事情怎么样?

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

How about something like this?

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();
    }
}
猥琐帝 2024-07-27 02:51:27

假设列表中包含的每个成员的 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 上输入了此内容并且没有编译器,所以上面所说的代码不能保证工作,但希望它能展示这个想法。

Assuming that GetHashCode() for every member contained in the list is implemented properly (and thus changes when an element changes) I'd imagine something along the lines of:

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

*Please be aware i typed this up on SO and do not have a compiler, so above stated code is in no way guarenteed to work, but hopefully it'll show the idea.

旧瑾黎汐 2024-07-27 02:51:27

您可以实现自己的列表,维护 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.
       }
    }
}

You could implement you're own list that maintains 2 internal lists... and instantiated version and tracking version... e.g.

//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.
       }
    }
}
硬不硬你别怂 2024-07-27 02:51:27

确保 T 是具有脏标志的对象的后代,并且让 IList 实现检查遍历列表脏标志的对象。

Make sure that T is a descendant of an object that has a dirty flag and have the IList implementation have a check for that which walks the list's dirty flags.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文