1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
4 namespace System.Activities.Presentation.Model
8 using System.Collections;
9 using System.Collections.Generic;
10 using System.Diagnostics.CodeAnalysis;
12 using System.Threading;
13 using System.Runtime.InteropServices;
15 internal class WeakKeyDictionary<K, V> : IDictionary<K, V>
17 private Dictionary<WeakKey, V> _internalDictionary;
18 private object _[....] = new object();
19 private bool _finalized;
21 internal WeakKeyDictionary()
23 _internalDictionary = new Dictionary<WeakKey, V>(new WeakComparer());
26 public WeakKeyDictionary(IEqualityComparer<K> comparer)
28 _internalDictionary = new Dictionary<WeakKey, V>(new WeakComparer(comparer));
31 // FXCop: this is not empty; we need to mark this so we know if a key
32 // still has an active dictionary at its finalization.
33 [SuppressMessage("Microsoft.Performance", "CA1821:RemoveEmptyFinalizers")]
39 public ICollection<K> Keys
43 List<K> list = new List<K>();
46 foreach (WeakKey key in _internalDictionary.Keys)
48 object k = key.Target;
59 public ICollection<V> Values
63 // make a copy of the values, so the during GC, the returned collection does not change.
64 return new List<V>(_internalDictionary.Values);
73 // Ensure a fairly accurate count.
77 return _internalDictionary.Count;
82 public bool IsReadOnly
89 [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = "LostKeyFinder's purpose is to get garbage collected as soon as posible")]
94 return _internalDictionary[new WeakKey(key)];
99 WeakKey k = new WeakKey(key);
102 _internalDictionary[k] = value;
104 // This looks a bit weird but the purpose of the lost key finder is to execute
105 // code in some future garbage collection phase so we immediately create some garbage.
106 new LostKeyFinder(this, k);
110 public bool TryGetValue(K key, out V value)
112 WeakKey k = new WeakKey(key);
115 return _internalDictionary.TryGetValue(k, out value);
119 [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = "LostKeyFinder's purpose is to get garbage collected as soon as posible")]
120 public void Add(K key, V value)
122 WeakKey k = new WeakKey(key);
125 _internalDictionary.Add(k, value);
127 // This looks a bit weird but the purpose of the lost key finder is to execute
128 // code in some future garbage collection phase so we immediately create some garbage.
129 new LostKeyFinder(this, k);
133 public bool ContainsKey(K key)
135 return _internalDictionary.ContainsKey(new WeakKey(key));
138 public bool Remove(K key)
142 return _internalDictionary.Remove(new WeakKey(key));
146 public void Add(KeyValuePair<K, V> item)
148 Add(item.Key, item.Value);
155 _internalDictionary.Clear();
159 public bool Contains(KeyValuePair<K, V> item)
165 result = _internalDictionary.TryGetValue(new WeakKey(item.Key), out value);
169 return value.Equals(item.Value);
177 public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
181 foreach (KeyValuePair<WeakKey, V> item in _internalDictionary)
183 KeyValuePair<K, V> kv = new KeyValuePair<K, V>((K)item.Key.Target, item.Value);
184 array[arrayIndex] = kv;
190 public bool Remove(KeyValuePair<K, V> item)
192 WeakKey key = new WeakKey(item.Key);
195 return _internalDictionary.Remove(key);
203 public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
205 List<WeakKey> lostKeys = null;
208 foreach (KeyValuePair<WeakKey, V> item in _internalDictionary)
210 object k = item.Key.Target;
213 yield return new KeyValuePair<K, V>((K)k, item.Value);
217 if (lostKeys == null)
219 lostKeys = new List<WeakKey>();
221 lostKeys.Add(item.Key);
225 // Recover any lost keys.
226 if (lostKeys != null)
230 foreach (WeakKey key in lostKeys)
232 _internalDictionary.Remove(key);
241 IEnumerator IEnumerable.GetEnumerator()
243 return GetEnumerator();
248 private void ScavangeLostKeys()
250 List<WeakKey> lostKeys = null;
253 foreach (WeakKey key in _internalDictionary.Keys)
257 if (lostKeys == null)
259 lostKeys = new List<WeakKey>();
265 if (lostKeys != null)
269 foreach (WeakKey key in lostKeys)
271 _internalDictionary.Remove(key);
277 private class WeakKey : WeakReference
279 private int _hashCode;
280 // private GCHandle _gcHandle;
282 public WeakKey(K key)
285 _hashCode = key.GetHashCode();
286 // Keep the key alive until it is explicitly collected
287 // _gcHandle = GCHandle.Alloc(this);
290 internal void Release()
295 public override int GetHashCode()
300 public override bool Equals(object obj)
306 if (obj.GetHashCode() != _hashCode)
310 if (obj != this && (!IsAlive || !obj.Equals(Target)))
318 private class WeakComparer : IEqualityComparer<WeakKey>
321 private IEqualityComparer<K> _comparer;
322 public WeakComparer()
326 public WeakComparer(IEqualityComparer<K> comparer)
328 _comparer = comparer;
331 public bool Equals(WeakKey x, WeakKey y)
333 if (x.GetHashCode() != y.GetHashCode())
337 if (object.ReferenceEquals(x, y))
341 object ref1 = x.Target;
346 object ref2 = y.Target;
352 if (_comparer != null)
354 return _comparer.Equals((K)ref1, (K)ref2);
358 return ref1.Equals(ref2);
362 public int GetHashCode(WeakKey obj)
364 return obj.GetHashCode();
368 private class LostKeyFinder
370 WeakKeyDictionary<K, V> _dictionary;
373 public LostKeyFinder(WeakKeyDictionary<K, V> dictionary, WeakKey key)
375 _dictionary = dictionary;
381 if (_dictionary._finalized || _key == null)
390 // if (!_key.IsAlive) {
391 if (_key.Target == null)
396 locked = Monitor.TryEnter(_dictionary._[....]);
397 _dictionary._internalDictionary.Remove(_key);
403 Monitor.Exit(_dictionary._[....]);
414 GC.ReRegisterForFinalize(this);
417 else if (_dictionary._internalDictionary.ContainsKey(_key))
419 GC.ReRegisterForFinalize(this);