Skip to content

Commit 0b67661

Browse files
committed
Added collection types and threading classes
1 parent ce486c5 commit 0b67661

14 files changed

+2185
-6
lines changed
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
namespace Hexa.NET.Utilities.Collections
2+
{
3+
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
5+
6+
/// <summary>
7+
/// Represents an observable dictionary that allows you to observe changes to its contents.
8+
/// </summary>
9+
[Serializable]
10+
public class ObservableDictionary<TKey, TValue> : ObservableCollection<ObservableKeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue> where TKey : notnull
11+
{
12+
/// <summary>
13+
/// Initializes a new instance of the <see cref="ObservableDictionary{TKey, TValue}"/> class.
14+
/// </summary>
15+
public ObservableDictionary()
16+
{
17+
}
18+
19+
/// <summary>
20+
/// Initializes a new instance of the <see cref="ObservableDictionary{TKey, TValue}"/> class with an existing collection.
21+
/// </summary>
22+
/// <param name="collection">An existing collection of key-value pairs.</param>
23+
public ObservableDictionary(IEnumerable<ObservableKeyValuePair<TKey, TValue>> collection) : base(collection)
24+
{
25+
}
26+
27+
/// <summary>
28+
/// Initializes a new instance of the <see cref="ObservableDictionary{TKey, TValue}"/> class with an existing list.
29+
/// </summary>
30+
/// <param name="list">An existing list of key-value pairs.</param>
31+
public ObservableDictionary(List<ObservableKeyValuePair<TKey, TValue>> list) : base(list)
32+
{
33+
}
34+
35+
/// <summary>
36+
/// Adds a key-value pair to the dictionary.
37+
/// </summary>
38+
/// <param name="key">The key to add.</param>
39+
/// <param name="value">The value associated with the key.</param>
40+
public virtual void Add(TKey key, TValue value)
41+
{
42+
if (ContainsKey(key))
43+
{
44+
throw new ArgumentException("The dictionary already contains the key");
45+
}
46+
Add(new ObservableKeyValuePair<TKey, TValue>() { Key = key, Value = value });
47+
}
48+
49+
/// <summary>
50+
/// Determines whether the dictionary contains the specified key.
51+
/// </summary>
52+
/// <param name="key">The key to check for.</param>
53+
/// <returns><c>true</c> if the dictionary contains the key; otherwise, <c>false</c>.</returns>
54+
public virtual bool ContainsKey(TKey key)
55+
{
56+
var r = ThisAsCollection().FirstOrDefault((i) => ObservableDictionary<TKey, TValue>.Equals(key, i.Key));
57+
58+
return !Equals(default(ObservableKeyValuePair<TKey, TValue>), r);
59+
}
60+
61+
/// <summary>
62+
/// Determines whether two keys are equal using the default equality comparer for the key type.
63+
/// </summary>
64+
/// <param name="a">The first key to compare.</param>
65+
/// <param name="b">The second key to compare.</param>
66+
/// <returns><c>true</c> if the keys are equal; otherwise, <c>false</c>.</returns>
67+
private static bool Equals(TKey a, TKey b)
68+
{
69+
return EqualityComparer<TKey>.Default.Equals(a, b);
70+
}
71+
72+
/// <summary>
73+
/// Converts the dictionary to an ObservableCollection of key-value pairs.
74+
/// </summary>
75+
/// <returns>An ObservableCollection of key-value pairs.</returns>
76+
private ObservableCollection<ObservableKeyValuePair<TKey, TValue>> ThisAsCollection()
77+
{
78+
return this;
79+
}
80+
81+
/// <summary>
82+
/// Gets a collection containing the keys of the dictionary.
83+
/// </summary>
84+
public ICollection<TKey> Keys
85+
{
86+
get { return (from i in ThisAsCollection() select i.Key).ToList(); }
87+
}
88+
89+
/// <summary>
90+
/// Removes all elements from the dictionary.
91+
/// </summary>
92+
public virtual new void Clear()
93+
{
94+
base.Clear();
95+
}
96+
97+
/// <summary>
98+
/// Removes the element with the specified key from the dictionary.
99+
/// </summary>
100+
/// <param name="key">The key of the element to remove.</param>
101+
/// <returns><c>true</c> if the element is successfully removed; otherwise, <c>false</c>.</returns>
102+
public virtual bool Remove(TKey key)
103+
{
104+
var remove = ThisAsCollection().Where(pair => ObservableDictionary<TKey, TValue>.Equals(key, pair.Key)).ToList();
105+
foreach (var pair in remove)
106+
{
107+
ThisAsCollection().Remove(pair);
108+
}
109+
return remove.Count > 0;
110+
}
111+
112+
/// <summary>
113+
/// Gets the value associated with the specified key.
114+
/// </summary>
115+
/// <param name="key">The key to locate in the dictionary.</param>
116+
/// <param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <typeparamref name="TValue"/> parameter.</param>
117+
/// <returns><c>true</c> if the dictionary contains an element with the specified key; otherwise, <c>false</c>.</returns>
118+
public virtual bool TryGetValue(TKey key, out TValue value)
119+
{
120+
#nullable disable
121+
value = default;
122+
#nullable restore
123+
var r = GetKvpByTheKey(key);
124+
if (r == null)
125+
{
126+
return false;
127+
}
128+
value = r.Value;
129+
return true;
130+
}
131+
132+
/// <summary>
133+
/// Gets the key-value pair associated with the specified key.
134+
/// </summary>
135+
/// <param name="key">The key to locate in the dictionary.</param>
136+
/// <returns>The key-value pair associated with the specified key, or <c>null</c> if the key is not found.</returns>
137+
private ObservableKeyValuePair<TKey, TValue> GetKvpByTheKey(TKey key)
138+
{
139+
#nullable disable
140+
return ThisAsCollection().FirstOrDefault((i) => i.Key.Equals(key));
141+
#nullable restore
142+
}
143+
144+
/// <summary>
145+
/// Gets a collection containing the values in the dictionary.
146+
/// </summary>
147+
public ICollection<TValue> Values
148+
{
149+
get { return (from i in ThisAsCollection() select i.Value).ToList(); }
150+
}
151+
152+
/// <summary>
153+
/// Gets or sets the value associated with the specified key.
154+
/// </summary>
155+
/// <param name="key">The key of the value to get or set.</param>
156+
/// <returns>The value associated with the specified key.</returns>
157+
public TValue this[TKey key]
158+
{
159+
get
160+
{
161+
TValue result;
162+
if (!TryGetValue(key, out result))
163+
{
164+
throw new ArgumentException("Key not found");
165+
}
166+
return result;
167+
}
168+
set
169+
{
170+
if (ContainsKey(key))
171+
{
172+
GetKvpByTheKey(key).Value = value;
173+
}
174+
else
175+
{
176+
Add(key, value);
177+
}
178+
}
179+
}
180+
181+
/// <summary>
182+
/// Adds a key-value pair to the dictionary.
183+
/// </summary>
184+
/// <param name="item">The key-value pair to add to the dictionary.</param>
185+
public virtual void Add(KeyValuePair<TKey, TValue> item)
186+
{
187+
Add(item.Key, item.Value);
188+
}
189+
190+
/// <summary>
191+
/// Determines whether the dictionary contains a specific key-value pair.
192+
/// </summary>
193+
/// <param name="item">The key-value pair to locate in the dictionary.</param>
194+
/// <returns><c>true</c> if the dictionary contains the specified key-value pair; otherwise, <c>false</c>.</returns>
195+
public virtual bool Contains(KeyValuePair<TKey, TValue> item)
196+
{
197+
var r = GetKvpByTheKey(item.Key);
198+
if (Equals(r, default(ObservableKeyValuePair<TKey, TValue>)))
199+
{
200+
return false;
201+
}
202+
return Equals(r.Value, item.Value);
203+
}
204+
205+
/// <summary>
206+
/// Copies the elements of the <see cref="ObservableDictionary{TKey, TValue}"/> to an array of key-value pairs, starting at the specified array index.
207+
/// </summary>
208+
/// <param name="array">The one-dimensional array of key-value pairs that is the destination of the elements copied from the dictionary. The array must have zero-based indexing.</param>
209+
/// <param name="arrayIndex">The zero-based index in the array at which copying begins.</param>
210+
public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
211+
{
212+
if (array == null)
213+
{
214+
throw new ArgumentNullException(nameof(array), "The destination array is null.");
215+
}
216+
217+
if (arrayIndex < 0 || arrayIndex >= array.Length)
218+
{
219+
throw new ArgumentOutOfRangeException(nameof(arrayIndex), "The array index is out of range.");
220+
}
221+
222+
if (array.Length - arrayIndex < Count)
223+
{
224+
throw new ArgumentException("The number of elements in the dictionary is greater than the available space from arrayIndex to the end of the destination array.");
225+
}
226+
227+
int i = arrayIndex;
228+
foreach (var pair in ThisAsCollection())
229+
{
230+
array[i] = new KeyValuePair<TKey, TValue>(pair.Key, pair.Value);
231+
i++;
232+
}
233+
}
234+
235+
/// <summary>
236+
/// Gets a value indicating whether the <see cref="ObservableDictionary{TKey, TValue}"/> is read-only.
237+
/// </summary>
238+
/// <value>true if the dictionary is read-only; otherwise, false. This property always returns false.</value>
239+
public bool IsReadOnly
240+
{
241+
get { return false; }
242+
}
243+
244+
/// <summary>
245+
/// Removes the first occurrence of a specific key and value from the dictionary.
246+
/// </summary>
247+
/// <param name="item">The key-value pair to remove from the dictionary.</param>
248+
/// <returns>true if the key-value pair was successfully removed; otherwise, false.</returns>
249+
public virtual bool Remove(KeyValuePair<TKey, TValue> item)
250+
{
251+
var r = GetKvpByTheKey(item.Key);
252+
if (Equals(r, default(ObservableKeyValuePair<TKey, TValue>)))
253+
{
254+
return false;
255+
}
256+
if (!Equals(r.Value, item.Value))
257+
{
258+
return false;
259+
}
260+
return ThisAsCollection().Remove(r);
261+
}
262+
263+
/// <summary>
264+
/// Returns an enumerator that iterates through the <see cref="ObservableDictionary{TKey, TValue}"/>.
265+
/// </summary>
266+
/// <returns>An enumerator for the <see cref="ObservableDictionary{TKey, TValue}"/>.</returns>
267+
public virtual new IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
268+
{
269+
return (from i in ThisAsCollection() select new KeyValuePair<TKey, TValue>(i.Key, i.Value)).ToList().GetEnumerator();
270+
}
271+
}
272+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
namespace Hexa.NET.Utilities.Collections
2+
{
3+
using System.ComponentModel;
4+
using System.Runtime.CompilerServices;
5+
6+
/// <summary>
7+
/// Represents a key-value pair that implements the <see cref="INotifyPropertyChanged"/> interface.
8+
/// </summary>
9+
[Serializable]
10+
public class ObservableKeyValuePair<TKey, TValue> : INotifyPropertyChanged where TKey : notnull
11+
{
12+
#nullable disable
13+
private TKey key;
14+
private TValue value;
15+
#nullable restore
16+
/// <summary>
17+
/// Gets or sets the key of the key-value pair.
18+
/// </summary>
19+
public TKey Key
20+
{
21+
get { return key; }
22+
set
23+
{
24+
key = value;
25+
OnPropertyChanged();
26+
}
27+
}
28+
29+
/// <summary>
30+
/// Gets or sets the value of the key-value pair.
31+
/// </summary>
32+
public TValue Value
33+
{
34+
get { return value; }
35+
set
36+
{
37+
this.value = value;
38+
OnPropertyChanged();
39+
}
40+
}
41+
42+
/// <inheritdoc/>
43+
[field: NonSerialized]
44+
public event PropertyChangedEventHandler? PropertyChanged;
45+
46+
/// <summary>
47+
/// Raises the <see cref="PropertyChanged"/> event.
48+
/// </summary>
49+
/// <param name="name">The name of the property that changed.</param>
50+
protected virtual void OnPropertyChanged([CallerMemberName] string name = "")
51+
{
52+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)