C#监听Dictionary、List的写入操作

前言

在开发中,对于内置值类型和string我们可以通过封装属性在Set 中监听写入操作,但是对于DictionaryList 等就不能监听到AddRemove 等写入操作。

所以一般采取两种方式监听它们的读写操作,一种是封装操作方法,间接进行监听,第二种就是重写AddRemove等方法。下面介绍第二种方法。

实现

下面是重写了Dictionary 的示例,List同理。

csharp 复制代码
using System;
using System.Collections.Generic;

// 定义一个委托类型,用于处理字典变化的事件
public delegate void DictionaryChangedEventHandler<TKey, TValue>(object sender, DictionaryChangedEventArgs<TKey, TValue> e);

// 定义一个事件参数类,用于封装字典变化的信息
public class DictionaryChangedEventArgs<TKey, TValue> : EventArgs
{
    // 变化的类型,可以是Add, Remove, Update或Clear
    public DictionaryChangedType ChangeType { get; set; }

    // 变化的键
    public TKey Key { get; set; }

    // 变化的值
    public TValue Value { get; set; }

    // 构造函数
    public DictionaryChangedEventArgs(DictionaryChangedType changeType, TKey key, TValue value)
    {
        ChangeType = changeType;
        Key = key;
        Value = value;
    }
}

// 定义一个枚举类型,用于表示字典变化的类型
public enum DictionaryChangedType
{
    Init,
    Add,
    Remove,
    Update,
    Clear,
}

// 定义一个继承自Dictionary<TKey,TValue>的类,用于触发字典变化的事件
public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    // 定义一个构造函数,用于接受一个IDictionary<TKey, TValue>类型的参数
    public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
    {
        base.Clear();
        foreach (var item in dictionary)
        {
            base.Add(item.Key, item.Value);
        }
        OnDictionaryChanged(new DictionaryChangedEventArgs<TKey, TValue>(DictionaryChangedType.Init, default, default));
    }

    public ObservableDictionary()
    {
        OnDictionaryChanged(new DictionaryChangedEventArgs<TKey, TValue>(DictionaryChangedType.Init, default, default));
    }

    // 定义一个事件,用于通知字典变化
    public event DictionaryChangedEventHandler<TKey, TValue> DictionaryChanged;

    // 重写Add方法,用于在添加元素时触发事件
    public new void Add(TKey key, TValue value)
    {
        base.Add(key, value);
        OnDictionaryChanged(new DictionaryChangedEventArgs<TKey, TValue>(DictionaryChangedType.Add, key, value));
    }

    // 重写Remove方法,用于在删除元素时触发事件
    public new bool Remove(TKey key)
    {
        if (base.TryGetValue(key, out TValue value))
        {
            base.Remove(key);
            OnDictionaryChanged(new DictionaryChangedEventArgs<TKey, TValue>(DictionaryChangedType.Remove, key, value));
            return true;
        }
        return false;
    }

    // 重写索引器,用于在更新元素时触发事件
    public new TValue this[TKey key]
    {
        get => base[key];
        set
        {
            if (base.ContainsKey(key))
            {
                base[key] = value;
                OnDictionaryChanged(new DictionaryChangedEventArgs<TKey, TValue>(DictionaryChangedType.Update, key, value));
            }
            else
            {
                Add(key, value);
            }
        }
    }

    // 重写Clear方法,用于在清空字典时触发事件
    public new void Clear()
    {
        base.Clear();
        OnDictionaryChanged(new DictionaryChangedEventArgs<TKey, TValue>(DictionaryChangedType.Clear, default, default));
    }

    // 定义一个虚方法,用于触发事件
    protected virtual void OnDictionaryChanged(DictionaryChangedEventArgs<TKey, TValue> e)
    {
        DictionaryChanged?.Invoke(this, e);
    }

    public void ResetSubscriptions()
    {
        DictionaryChanged = null;
    }
}

使用示例

csharp 复制代码
    public void Test()
    {
        // 创建一个ObservableDictionary实例
        var dict = new ObservableDictionary<string, int>();

        // 注册事件处理程序,用于输出字典变化的信息
        dict.DictionaryChanged += (sender, e) =>
        {
            Debug.Log($"ChangeType: {e.ChangeType}, Key: {e.Key}, Value: {e.Value}");
        };

        // 添加元素
        dict.Add("a", 1);
        dict.Add("b", 2);

        // 删除元素
        dict.Remove("a");

        // 更新元素
        dict["b"] = 3;
        dict["c"] = 4;

        Dictionary<string, int> newDic = new Dictionary<string, int>
        {
            { "acd", 120 }
        };
        Debug.LogError(((ObservableDictionary<string, int>)newDic).Count);
        var newDic1 = new ObservableDictionary<string, int>(newDic);
        Debug.LogError(newDic1.Count);
        // 清空字典
        dict.Clear();
    }
相关推荐
阿巴~阿巴~36 分钟前
Linux 第一个系统程序 - 进度条
linux·服务器·bash
我科绝伦(Huanhuan Zhou)1 小时前
华为泰山服务器重启后出现 XFS 文件系统磁盘“不识别”(无法挂载或访问),但挂载点目录仍在且无数据
运维·服务器·华为
望获linux2 小时前
【Linux基础知识系列】第四十三篇 - 基础正则表达式与 grep/sed
linux·运维·服务器·开发语言·前端·操作系统·嵌入式软件
网硕互联的小客服5 小时前
服务器经常出现蓝屏是什么原因导致的?如何排查和修复?
运维·服务器·stm32·单片机·网络安全
witton5 小时前
Go语言网络游戏服务器模块化编程
服务器·开发语言·游戏·golang·origin·模块化·耦合
成都极云科技5 小时前
成都算力租赁新趋势:H20 八卡服务器如何重塑 AI 产业格局?
大数据·服务器·人工智能·云计算·gpu算力
喜欢吃豆5 小时前
从零构建MCP服务器:FastMCP实战指南
运维·服务器·人工智能·python·大模型·mcp
刘阿宾5 小时前
【华为昇腾|CUDA】服务器A6000显卡部署LLM实战记录
服务器·华为·语言模型·gpu算力·kylin
海外空间恒创科技5 小时前
恒创科技:香港站群服务器做seo站群优化效果如何
运维·服务器·科技
搬码临时工5 小时前
内网服务器怎么设置公网远程访问? windows桌面连接和Linux自带SSH外网异地跨网用完整步骤教程
运维·服务器·ssh