#if NET20 || NET30 || NET35 || !NET_4_6 using System.Collections.Generic; using System.Runtime.InteropServices; using LinqInternal.Collections.ThreadSafe; // Note: the class ConditionalWeakTable is meant to be a weak key dictionary (not a weak value dictionary) // // FROM MSDN: // // The ConditionalWeakTable class differs from other collection objects in its management of the object lifetime of keys stored in the collection. // Ordinarily, when an object is stored in a collection, its lifetime lasts until it is removed (and there are no additional references to the object) // or until the collection object itself is destroyed. // // However, in the ConditionalWeakTable class, adding a key/value pair to the table does not ensure that the key will persist, // even if it can be reached directly from a value stored in the table (for example, if the table contains one key, A, with a value V1, and a second key, B, with a value P2 that contains a reference to A). // Instead, ConditionalWeakTable automatically removes the key/value entry as soon as no other references to a key exist outside the table. The example provides an illustration. // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ // // The above means that we keep a weak reference to the key but an strong reference to the value // This is the kind of dictionary that Theraot.Collections.ThreadSafe.WeakDictionary is // Since microsoft's is failing tests, I'll replace their implementation with WeakDictionary... // Because at least I know how to maintain WeakDictionary also... // Having WeakDictionary and ConditionalWeakTable is kind of redundant. // In fact this was one of the intentions behind creating WeakDictionary in the first place namespace System.Runtime.CompilerServices { [ComVisible(false)] public sealed class ConditionalWeakTable where TKey : class where TValue : class { private readonly WeakDictionary _wrapped; public ConditionalWeakTable() { _wrapped = new WeakDictionary(); } /// /// Represents a method that creates a non-default value to add as part of a key/value pair to a object. /// /// The key that belongs to the value to create. /// An instance of a reference type that represents the value to attach to the specified key. public delegate TValue CreateValueCallback(TKey key); internal ICollection Keys { get { return _wrapped.Keys; } } /// /// Adds a key to the table. /// /// The key to add. key represents the object to which the property is attached. /// The key's property value. public void Add(TKey key, TValue value) { if (key == null) { throw new ArgumentNullException("key"); } _wrapped.AddNew(key, value); } /// /// Atomically searches for a specified key in the table and returns the corresponding value. If the key does not exist in the table, the method invokes the default constructor of the class that represents the table's value to create a value that is bound to the specified key. /// /// The key to search for. key represents the object to which the property is attached. /// The value that corresponds to key, if key already exists in the table; otherwise, a new value created by the default constructor of the class defined by the TValue generic type parameter. public TValue GetOrCreateValue(TKey key) { if (key == null) { throw new ArgumentNullException("key"); } return PrivateGetValue(key, k => Activator.CreateInstance()); } /// /// Atomically searches for a specified key in the table and returns the corresponding value.If the key does not exist in the table, the method invokes a callback method to create a value that is bound to the specified key. /// /// The key to search for. key represents the object to which the property is attached. /// A delegate to a method that can create a value for the given key. It has a single parameter of type TKey, and returns a value of type TValue. /// The value attached to key, if key already exists in the table; otherwise, the new value returned by the createValueCallback delegate. public TValue GetValue(TKey key, CreateValueCallback createValueCallback) { if (key == null) { throw new ArgumentNullException("key"); } if (createValueCallback == null) { throw new ArgumentNullException("createValueCallback"); } return _wrapped.GetOrAdd(key, input => createValueCallback(input)); } private TValue PrivateGetValue(TKey key, Func createValueCallback) { return _wrapped.GetOrAdd(key, createValueCallback); } /// /// Removes a key and its value from the table. /// /// The key to remove. /// /// true if the key is found and removed; otherwise, false. /// public bool Remove(TKey key) { if (key == null) { throw new ArgumentNullException("key"); } return _wrapped.Remove(key); } /// /// Gets the value of the specified key. /// /// The key that represents an object with an attached property. /// When this method returns, contains the attached property value. If key is not found, value contains the default value. /// /// true if the key is found; otherwise, false. /// public bool TryGetValue(TKey key, out TValue value) { if (key == null) { throw new ArgumentNullException("key"); } return _wrapped.TryGetValue(key, out value); } } } #endif