#endregion
- #region Internal members
-
- //--------------------------------------------------------------------------------------------
- // Find a key that equals (value equality) with the given key - don't use in perf critical path
- // Note that it calls out to Object.Equals which may calls the override version of Equals
- // and that may take locks and leads to deadlock
- // Currently it is only used by WinRT event code and you should only use this function
- // if you know for sure that either you won't run into dead locks or you need to live with the
- // possiblity
- //--------------------------------------------------------------------------------------------
- [FriendAccessAllowed]
- internal TKey FindEquivalentKeyUnsafe(TKey key, out TValue value)
- {
- lock (_lock)
- {
- return _container.FindEquivalentKeyUnsafe(key, out value);
- }
- }
-
- //--------------------------------------------------------------------------------------------
- // Returns a collection of keys - don't use in perf critical path
- //--------------------------------------------------------------------------------------------
- internal ICollection<TKey> Keys
- {
- get
- {
- lock (_lock)
- {
- return _container.Keys;
- }
- }
- }
-
- //--------------------------------------------------------------------------------------------
- // Returns a collection of values - don't use in perf critical path
- //--------------------------------------------------------------------------------------------
- internal ICollection<TValue> Values
- {
- get
- {
- lock (_lock)
- {
- return _container.Values;
- }
- }
- }
-
- #endregion
-
#region Private Members
//----------------------------------------------------------------------------------------
return newContainer;
}
- internal ICollection<TKey> Keys
- {
- get
- {
- var list = new List<TKey>();
-
- for (int bucket = 0; bucket < _buckets.Length; ++bucket)
- {
- for (int entriesIndex = _buckets[bucket]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].Next)
- {
- TKey thisKey = JitHelpers.UnsafeCast<TKey>(_entries[entriesIndex].depHnd.GetPrimary());
- if (thisKey != null)
- {
- list.Add(thisKey);
- }
- }
- }
-
- GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles.
- return list;
- }
- }
-
- internal ICollection<TValue> Values
- {
- get
- {
- var list = new List<TValue>();
-
- for (int bucket = 0; bucket < _buckets.Length; ++bucket)
- {
- for (int entriesIndex = _buckets[bucket]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].Next)
- {
- object primary, secondary;
- primary = _entries[entriesIndex].depHnd.GetPrimaryAndSecondary(out secondary);
-
- // Now that we've secured a strong reference to the secondary, must check the primary again
- // to ensure it didn't expire (otherwise, we open a race where TryGetValue misreports an
- // expired key as a live key with a null value.)
- if (primary != null)
- {
- list.Add(JitHelpers.UnsafeCast<TValue>(secondary));
- }
- }
- }
-
- GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles.
- return list;
- }
- }
-
- internal TKey FindEquivalentKeyUnsafe(TKey key, out TValue value)
- {
- for (int bucket = 0; bucket < _buckets.Length; ++bucket)
- {
- for (int entriesIndex = _buckets[bucket]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].Next)
- {
- if (_entries[entriesIndex].HashCode == -1)
- {
- continue; // removed entry whose handle is awaiting condemnation by the finalizer.
- }
-
- object thisKey, thisValue;
- thisKey = _entries[entriesIndex].depHnd.GetPrimaryAndSecondary(out thisValue);
- if (Equals(thisKey, key))
- {
- GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles.
- value = JitHelpers.UnsafeCast<TValue>(thisValue);
- return JitHelpers.UnsafeCast<TKey>(thisKey);
- }
- }
- }
-
- GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles.
- value = default(TValue);
- return null;
- }
-
//----------------------------------------------------------------------------------------
// Precondition:
// Must hold _lock.
{
lock (ManagedEventRegistrationImpl.s_eventRegistrations)
{
- count += ManagedEventRegistrationImpl.s_eventRegistrations.Keys.Count;
+ foreach (var item in ManagedEventRegistrationImpl.s_eventRegistrations)
+ count++;
}
}
return (object)Marshal.GetRawIUnknownForComObjectNoAddRef(target);
}
+ private static object FindEquivalentKeyUnsafe(ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTable, object handler, out EventRegistrationTokenListWithCount tokens)
+ {
+ foreach (KeyValuePair<object, EventRegistrationTokenListWithCount> item in registrationTable)
+ {
+ if (Object.Equals(item.Key, handler))
+ {
+ tokens = item.Value;
+ return item.Key;
+ }
+ }
+ tokens = null;
+ return null;
+ }
+
internal static void AddEventHandler<T>(Func<T, EventRegistrationToken> addMethod,
Action<EventRegistrationToken> removeMethod,
T handler)
// will be added into B's token list, but once we unsubscribe B, we might end up removing
// the last token in C, and that may lead to crash.
//
- object key = registrationTokens.FindEquivalentKeyUnsafe(handler, out tokens);
+ object key = FindEquivalentKeyUnsafe(registrationTokens, handler, out tokens);
if (key == null)
{
tokens = new EventRegistrationTokenListWithCount(tokenListCount, token);
// It actually doesn't matter which delegate - as long as it matches
// Note that inside TryGetValueWithValueEquality we assumes that any delegate
// with the same value equality would have the same hash code
- object key = registrationTokens.FindEquivalentKeyUnsafe(handler, out tokens);
+ object key = FindEquivalentKeyUnsafe(registrationTokens, handler, out tokens);
Debug.Assert((key != null && tokens != null) || (key == null && tokens == null),
"key and tokens must be both null or non-null");
if (tokens == null)
{
// Copy all tokens to tokensToRemove array which later we'll call removeMethod on
// outside this lock
- foreach (EventRegistrationTokenListWithCount tokens in registrationTokens.Values)
+ foreach (KeyValuePair<object, EventRegistrationTokenListWithCount> item in registrationTokens)
{
- tokens.CopyTo(tokensToRemove);
+ item.Value.CopyTo(tokensToRemove);
}
// Clear the table - at this point all event handlers are no longer in the cache
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
return new TaskScheduler[] { s_defaultTaskScheduler };
}
- ICollection<TaskScheduler> schedulers = s_activeTaskSchedulers.Keys;
+ List<TaskScheduler> schedulers = new List<TaskScheduler>();
+ foreach (var item in s_activeTaskSchedulers)
+ {
+ schedulers.Add(item.Key);
+ }
+
if (!schedulers.Contains(s_defaultTaskScheduler))
{
// Make sure the default is included, in case the debugger attached
schedulers.Add(s_defaultTaskScheduler);
}
- var arr = new TaskScheduler[schedulers.Count];
- schedulers.CopyTo(arr, 0);
+ var arr = schedulers.ToArray();
foreach (var scheduler in arr)
{
Debug.Assert(scheduler != null, "Table returned an incorrect Count or CopyTo failed");