Orion's Studio.

手写一个能监听内容变化的字典!

2017/03/26

我绝对(不)是一个标题党

问题的产生

今日任务————门禁刷卡:

只有当一定数量的人在很短间隔内刷卡才能芝麻开门!一旦到达时间还没有满足人数就会清零。

一开始把「改变容器内容」和「改变显示效果」和「控制大门洞开」分为好几条语句执行,但是这一点都不优雅!

为什么不能在内容发生变化时自动触发事件呢???

想要一个容器,当容器内元素的数量发生变化时就能触发一个事件!

于是乎第一条解决方案

没错那就是 ObservableCollection 类,这个类有个神奇的 CollectionChanged 的事件,一旦内容的数量发生变化就会调用(类似于指针,地址变而不是内容变)

这在容器内只保存「id号码」时相当得好用!

但是我需要同时保存「id号码」和「用户信息」而且这两者不便于组合时就很尴尬了。。。

我一开始想到的是用Tuple,但是写出来代码贼丑而且效率贼低

だから、

咱们来手写一个能监听内容变化的字典吧!

啊,已经写不动了,于是直接代码呈上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

// 包含EventHandler
using System;
// 包含KeyValuePair
using System.Collections.Generic;

namespace VehicleSystem.tools
{
// TK(Templete Key),TV(Templete Value)分别是键和值的泛型
public class ObservableDictionary<TK,TV>
{
// 实际上存值的字典
private readonly Dictionary<TK, TV> _dic = new Dictionary<TK, TV>();

// 添值前触发的事件
public event EventHandler<KeyValuePair<TK, TV>> BeforeAdd;

// 添值后触发的事件
public event EventHandler<KeyValuePair<TK, TV>> AfterAdd;

// 清空前触发的事件
public event EventHandler<EventArgs> BeforeClear;

// 清空后触发的事件
public event EventHandler<EventArgs> AfterClear;

// 获取元素数时触发的事件
public event EventHandler<EventArgs> OnGetCount;

// 获取元素键时触发的事件
public event EventHandler<EventArgs> OnGetKeys;

// 获取元素值时触发的事件
public event EventHandler<EventArgs> OnGetValues;

// 元素数发生变化时触发的事件
public event EventHandler<EventArgs> CollectionChanged;

public int Count
{
get
{
// ?运算符代表可为空类型,为空时则不执行函数
OnGetCount?.Invoke(this,null);
return _dic.Count;
}
}

public Dictionary<TK, TV>.KeyCollection Keys
{
get
{
OnGetKeys?.Invoke(this, null);
return _dic.Keys;
}
}

public Dictionary<TK,TV>.ValueCollection Values
{
get
{
OnGetValues?.Invoke(this, null);
return _dic.Values;
}
}

// 索引器
public TV this[TK index]
{
get
{
return _dic[index];
}
set
{
_dic[index] = value;
CollectionChanged?.Invoke(this, null);
}
}

public void Add(TK key, TV value)
{
BeforeAdd?.Invoke(this, new KeyValuePair<TK, TV>(key, value));
_dic.Add(key, value);
AfterAdd?.Invoke(this, new KeyValuePair<TK, TV>(key, value));
CollectionChanged?.Invoke(this, null);
}

public void Clear()
{
BeforeClear?.Invoke(this, null);
_dic.Clear();
AfterClear?.Invoke(this, null);
CollectionChanged?.Invoke(this, null);
}
}
}

当然还不是很完美(比如 CollectionChanged 拆解成了四个事件,不过更清晰了有木有!!!)

具体使用的方法如下(节选):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 声明字典,键名存「id号码」,键值存「用户信息」
private readonly ObservableDictionary<string, string> _staffs = new ObservableDictionary<string, string>();

// 取出某个用户信息
_staffs["key"]
_staffs.Values.ToArray()[0]

// 绑定事件
_staffs.AfterAdd += _staffs_AfterAdd;

private void _staffs_AfterAdd(object sender, KeyValuePair<string, string> e)
{
e.Key ...
e.Value ...
}

写文章一共花了我50分钟唉,每天都这么写岂不是要累趴。。。

2017年3月27日更新

实现 CollectionChanged 事件

CATALOG
  1. 1. 我绝对(不)是一个标题党
    1. 1.1. 问题的产生
    2. 1.2. 于是乎第一条解决方案
    3. 1.3. 咱们来手写一个能监听内容变化的字典吧!
      1. 1.3.1. 2017年3月27日更新