Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Base / MS / Internal / WeakEventTable.cs / 1 / WeakEventTable.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Storage for the "weak event listener" pattern. // See WeakEventManager.cs for an overview. // //--------------------------------------------------------------------------- using System; using System.Diagnostics; // Debug using System.Collections; // Hashtable using System.Collections.Specialized; // HybridDictionary using System.Runtime.CompilerServices; // RuntimeHelpers using System.Security; // [SecurityCritical,SecurityTreatAsSafe] using System.Threading; // [ThreadStatic] using System.Windows; // WeakEventManager using System.Windows.Threading; // DispatcherObject using MS.Utility; // FrugalList namespace MS.Internal { ////// This class manages the correspondence between event types and /// event managers, in support of the "weak event listener" pattern. /// It also stores data on behalf of the managers; a manager can store /// data of its own choosing, indexed by the pair (manager, source). /// internal class WeakEventTable : DispatcherObject { #region Constructors // // Constructors // ////// Create a new instance of WeakEventTable. /// ////// Critical: This code calls into Link demanded methods /// (AppDomain.DomainUnload and AppDomain.ProcessExit) to attach handlers /// TreatAsSafe: This code does not take any parameter or return state. /// It simply attaches private call back. /// [SecurityCritical,SecurityTreatAsSafe] private WeakEventTable() { WeakEventTableShutDownListener listener = new WeakEventTableShutDownListener(this); } #endregion Constructors #region Internal Properties // // Internal Properties // ////// Return the WeakEventTable for the current thread /// internal static WeakEventTable CurrentWeakEventTable { get { // _currentTable is [ThreadStatic], so there's one per thread if (_currentTable == null) { _currentTable = new WeakEventTable(); } return _currentTable; } } ////// Take a read-lock on the table, and return the IDisposable. /// Queries to the table should occur within a /// "using (Table.ReadLock) { ... }" clause, except for queries /// that are already within a write lock. /// internal IDisposable ReadLock { get { return _lock.ReadLock; } } ////// Take a write-lock on the table, and return the IDisposable. /// All modifications to the table should occur within a /// "using (Table.WriteLock) { ... }" clause. /// internal IDisposable WriteLock { get { return _lock.WriteLock; } } ////// Get or set the manager instance for the given type. /// internal WeakEventManager this[Type managerType] { get { return (WeakEventManager)_managerTable[managerType]; } set { _managerTable[managerType] = value; } } ////// Get or set the data stored by the given manager for the given source. /// internal object this[WeakEventManager manager, object source] { get { EventKey key = new EventKey(manager, source); object result = _dataTable[key]; return result; } set { EventKey key = new EventKey(manager, source, true); _dataTable[key] = value; } } ////// Indicates whether cleanup is enabled. /// ////// Normally cleanup is always enabled, but a perf test environment might /// want to disable cleanup so that it doesn't interfere with the real /// perf measurements. /// internal bool IsCleanupEnabled { get { return _cleanupEnabled; } set { _cleanupEnabled = value; } } #endregion Internal Properties #region Internal Methods // // Internal Methods // ////// Remove the data for the given manager and source. /// internal void Remove(WeakEventManager manager, object source) { EventKey key = new EventKey(manager, source); _dataTable.Remove(key); } ////// Schedule a cleanup pass. This can be called from any thread. /// internal void ScheduleCleanup() { // only the first request after a previous cleanup should schedule real work if (Interlocked.Increment(ref _cleanupRequests) == 1) { Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new DispatcherOperationCallback(CleanupOperation), null); } } ////// Perform a cleanup pass. /// internal static bool Cleanup() { return CurrentWeakEventTable.Purge(false); } #endregion Internal Methods #region Private Methods // // Private Methods // // run a cleanup pass private object CleanupOperation(object arg) { // allow new requests, even if cleanup is disabled Interlocked.Exchange(ref _cleanupRequests, 0); if (IsCleanupEnabled) { Purge(false); } return null; } // remove dead entries. When purgeAll is true, remove all entries. private bool Purge(bool purgeAll) { bool foundDirt = false; using (this.WriteLock) { // copy the keys into a separate array, so that later on // we can change the table while iterating over the keys ICollection ic = _dataTable.Keys; EventKey[] keys = new EventKey[ic.Count]; ic.CopyTo(keys, 0); for (int i=keys.Length-1; i>=0; --i) { object source = keys[i].Source; foundDirt |= keys[i].Manager.PurgeInternal(source, _dataTable[keys[i]], purgeAll); // if source has been GC'd, remove its data if (!purgeAll && source == null) { _dataTable.Remove(keys[i]); } } if (purgeAll) { _managerTable.Clear(); _dataTable.Clear(); } } return foundDirt; } // do the final cleanup when the Dispatcher or AppDomain is shut down private void OnShutDown() { Purge(true); // remove the table from thread storage _currentTable = null; } #endregion Private Methods #region Private Fields // // Private Fields // private Hashtable _managerTable = new Hashtable(); // maps manager type -> instance private Hashtable _dataTable = new Hashtable(); // maps EventKey -> data ReaderWriterLockWrapper _lock = new ReaderWriterLockWrapper(); private int _cleanupRequests; private bool _cleanupEnabled = true; [ThreadStatic] private static WeakEventTable _currentTable; // one table per thread #endregion Private Fields #region WeakEventTableShutDownListener private sealed class WeakEventTableShutDownListener : ShutDownListener { ////// Critical: accesses AppDomain.DomainUnload event /// TreatAsSafe: This code does not take any parameter or return state. /// It simply attaches private callbacks. /// [SecurityCritical,SecurityTreatAsSafe] public WeakEventTableShutDownListener(WeakEventTable target) : base(target) { } internal override void OnShutDown(object target) { WeakEventTable table = (WeakEventTable)target; table.OnShutDown(); } } #endregion WeakEventTableShutDownListener #region Table Keys // the key for the data table:private struct EventKey { internal EventKey(WeakEventManager manager, object source, bool useWeakRef) { _manager = manager; _source = new WeakReference(source); _hashcode = unchecked(manager.GetHashCode() + RuntimeHelpers.GetHashCode(source)); } internal EventKey(WeakEventManager manager, object source) { _manager = manager; _source = source; _hashcode = unchecked(manager.GetHashCode() + RuntimeHelpers.GetHashCode(source)); } internal object Source { get { return ((WeakReference)_source).Target; } } internal WeakEventManager Manager { get { return _manager; } } public override int GetHashCode() { #if DEBUG WeakReference wr = _source as WeakReference; object source = (wr != null) ? wr.Target : _source; if (source != null) { int hashcode = unchecked(_manager.GetHashCode() + RuntimeHelpers.GetHashCode(source)); Debug.Assert(hashcode == _hashcode, "hashcodes disagree"); } #endif return _hashcode; } public override bool Equals(object o) { if (o is EventKey) { WeakReference wr; EventKey ek = (EventKey)o; if (_manager != ek._manager || _hashcode != ek._hashcode) return false; wr = this._source as WeakReference; object s1 = (wr != null) ? wr.Target : this._source; wr = ek._source as WeakReference; object s2 = (wr != null) ? wr.Target : ek._source; if (s1!=null && s2!=null) return (s1 == s2); else return (_source == ek._source); } else { return false; } } public static bool operator==(EventKey key1, EventKey key2) { return key1.Equals(key2); } public static bool operator!=(EventKey key1, EventKey key2) { return !key1.Equals(key2); } WeakEventManager _manager; object _source; // lookup: direct ref; In table: WeakRef int _hashcode; // cached, in case source is GC'd } #endregion Table Keys } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // // Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Storage for the "weak event listener" pattern. // See WeakEventManager.cs for an overview. // //--------------------------------------------------------------------------- using System; using System.Diagnostics; // Debug using System.Collections; // Hashtable using System.Collections.Specialized; // HybridDictionary using System.Runtime.CompilerServices; // RuntimeHelpers using System.Security; // [SecurityCritical,SecurityTreatAsSafe] using System.Threading; // [ThreadStatic] using System.Windows; // WeakEventManager using System.Windows.Threading; // DispatcherObject using MS.Utility; // FrugalList namespace MS.Internal { ////// This class manages the correspondence between event types and /// event managers, in support of the "weak event listener" pattern. /// It also stores data on behalf of the managers; a manager can store /// data of its own choosing, indexed by the pair (manager, source). /// internal class WeakEventTable : DispatcherObject { #region Constructors // // Constructors // ////// Create a new instance of WeakEventTable. /// ////// Critical: This code calls into Link demanded methods /// (AppDomain.DomainUnload and AppDomain.ProcessExit) to attach handlers /// TreatAsSafe: This code does not take any parameter or return state. /// It simply attaches private call back. /// [SecurityCritical,SecurityTreatAsSafe] private WeakEventTable() { WeakEventTableShutDownListener listener = new WeakEventTableShutDownListener(this); } #endregion Constructors #region Internal Properties // // Internal Properties // ////// Return the WeakEventTable for the current thread /// internal static WeakEventTable CurrentWeakEventTable { get { // _currentTable is [ThreadStatic], so there's one per thread if (_currentTable == null) { _currentTable = new WeakEventTable(); } return _currentTable; } } ////// Take a read-lock on the table, and return the IDisposable. /// Queries to the table should occur within a /// "using (Table.ReadLock) { ... }" clause, except for queries /// that are already within a write lock. /// internal IDisposable ReadLock { get { return _lock.ReadLock; } } ////// Take a write-lock on the table, and return the IDisposable. /// All modifications to the table should occur within a /// "using (Table.WriteLock) { ... }" clause. /// internal IDisposable WriteLock { get { return _lock.WriteLock; } } ////// Get or set the manager instance for the given type. /// internal WeakEventManager this[Type managerType] { get { return (WeakEventManager)_managerTable[managerType]; } set { _managerTable[managerType] = value; } } ////// Get or set the data stored by the given manager for the given source. /// internal object this[WeakEventManager manager, object source] { get { EventKey key = new EventKey(manager, source); object result = _dataTable[key]; return result; } set { EventKey key = new EventKey(manager, source, true); _dataTable[key] = value; } } ////// Indicates whether cleanup is enabled. /// ////// Normally cleanup is always enabled, but a perf test environment might /// want to disable cleanup so that it doesn't interfere with the real /// perf measurements. /// internal bool IsCleanupEnabled { get { return _cleanupEnabled; } set { _cleanupEnabled = value; } } #endregion Internal Properties #region Internal Methods // // Internal Methods // ////// Remove the data for the given manager and source. /// internal void Remove(WeakEventManager manager, object source) { EventKey key = new EventKey(manager, source); _dataTable.Remove(key); } ////// Schedule a cleanup pass. This can be called from any thread. /// internal void ScheduleCleanup() { // only the first request after a previous cleanup should schedule real work if (Interlocked.Increment(ref _cleanupRequests) == 1) { Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new DispatcherOperationCallback(CleanupOperation), null); } } ////// Perform a cleanup pass. /// internal static bool Cleanup() { return CurrentWeakEventTable.Purge(false); } #endregion Internal Methods #region Private Methods // // Private Methods // // run a cleanup pass private object CleanupOperation(object arg) { // allow new requests, even if cleanup is disabled Interlocked.Exchange(ref _cleanupRequests, 0); if (IsCleanupEnabled) { Purge(false); } return null; } // remove dead entries. When purgeAll is true, remove all entries. private bool Purge(bool purgeAll) { bool foundDirt = false; using (this.WriteLock) { // copy the keys into a separate array, so that later on // we can change the table while iterating over the keys ICollection ic = _dataTable.Keys; EventKey[] keys = new EventKey[ic.Count]; ic.CopyTo(keys, 0); for (int i=keys.Length-1; i>=0; --i) { object source = keys[i].Source; foundDirt |= keys[i].Manager.PurgeInternal(source, _dataTable[keys[i]], purgeAll); // if source has been GC'd, remove its data if (!purgeAll && source == null) { _dataTable.Remove(keys[i]); } } if (purgeAll) { _managerTable.Clear(); _dataTable.Clear(); } } return foundDirt; } // do the final cleanup when the Dispatcher or AppDomain is shut down private void OnShutDown() { Purge(true); // remove the table from thread storage _currentTable = null; } #endregion Private Methods #region Private Fields // // Private Fields // private Hashtable _managerTable = new Hashtable(); // maps manager type -> instance private Hashtable _dataTable = new Hashtable(); // maps EventKey -> data ReaderWriterLockWrapper _lock = new ReaderWriterLockWrapper(); private int _cleanupRequests; private bool _cleanupEnabled = true; [ThreadStatic] private static WeakEventTable _currentTable; // one table per thread #endregion Private Fields #region WeakEventTableShutDownListener private sealed class WeakEventTableShutDownListener : ShutDownListener { ////// Critical: accesses AppDomain.DomainUnload event /// TreatAsSafe: This code does not take any parameter or return state. /// It simply attaches private callbacks. /// [SecurityCritical,SecurityTreatAsSafe] public WeakEventTableShutDownListener(WeakEventTable target) : base(target) { } internal override void OnShutDown(object target) { WeakEventTable table = (WeakEventTable)target; table.OnShutDown(); } } #endregion WeakEventTableShutDownListener #region Table Keys // the key for the data table:private struct EventKey { internal EventKey(WeakEventManager manager, object source, bool useWeakRef) { _manager = manager; _source = new WeakReference(source); _hashcode = unchecked(manager.GetHashCode() + RuntimeHelpers.GetHashCode(source)); } internal EventKey(WeakEventManager manager, object source) { _manager = manager; _source = source; _hashcode = unchecked(manager.GetHashCode() + RuntimeHelpers.GetHashCode(source)); } internal object Source { get { return ((WeakReference)_source).Target; } } internal WeakEventManager Manager { get { return _manager; } } public override int GetHashCode() { #if DEBUG WeakReference wr = _source as WeakReference; object source = (wr != null) ? wr.Target : _source; if (source != null) { int hashcode = unchecked(_manager.GetHashCode() + RuntimeHelpers.GetHashCode(source)); Debug.Assert(hashcode == _hashcode, "hashcodes disagree"); } #endif return _hashcode; } public override bool Equals(object o) { if (o is EventKey) { WeakReference wr; EventKey ek = (EventKey)o; if (_manager != ek._manager || _hashcode != ek._hashcode) return false; wr = this._source as WeakReference; object s1 = (wr != null) ? wr.Target : this._source; wr = ek._source as WeakReference; object s2 = (wr != null) ? wr.Target : ek._source; if (s1!=null && s2!=null) return (s1 == s2); else return (_source == ek._source); } else { return false; } } public static bool operator==(EventKey key1, EventKey key2) { return key1.Equals(key2); } public static bool operator!=(EventKey key1, EventKey key2) { return !key1.Equals(key2); } WeakEventManager _manager; object _source; // lookup: direct ref; In table: WeakRef int _hashcode; // cached, in case source is GC'd } #endregion Table Keys } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- AnnotationResource.cs
- XPathBuilder.cs
- CacheVirtualItemsEvent.cs
- ObjectManager.cs
- PasswordPropertyTextAttribute.cs
- InputScopeNameConverter.cs
- DefaultClaimSet.cs
- Exceptions.cs
- InertiaRotationBehavior.cs
- CachedTypeface.cs
- WebPartDisplayMode.cs
- PolicyValidationException.cs
- metadatamappinghashervisitor.hashsourcebuilder.cs
- XmlSchemaObjectCollection.cs
- QueryAccessibilityHelpEvent.cs
- FigureHelper.cs
- TraversalRequest.cs
- SqlMethodCallConverter.cs
- ManipulationDeltaEventArgs.cs
- XPathNavigatorKeyComparer.cs
- ActivityBuilderXamlWriter.cs
- IndexerNameAttribute.cs
- WeakEventTable.cs
- MetadataArtifactLoaderFile.cs
- GB18030Encoding.cs
- QueryCursorEventArgs.cs
- GrammarBuilder.cs
- SubclassTypeValidatorAttribute.cs
- WizardPanelChangingEventArgs.cs
- ListSurrogate.cs
- CaseInsensitiveHashCodeProvider.cs
- ItemsPanelTemplate.cs
- DefaultClaimSet.cs
- CqlParserHelpers.cs
- PolicyFactory.cs
- RSAPKCS1KeyExchangeDeformatter.cs
- UriTemplateVariableQueryValue.cs
- XmlFormatReaderGenerator.cs
- listitem.cs
- InheritanceUI.cs
- OpenCollectionAsyncResult.cs
- Tablet.cs
- AddingNewEventArgs.cs
- XmlHierarchyData.cs
- SqlRowUpdatedEvent.cs
- Int32Storage.cs
- SynchronizedDispatch.cs
- JsonObjectDataContract.cs
- RelatedEnd.cs
- FieldCollectionEditor.cs
- HttpAsyncResult.cs
- Timeline.cs
- DynamicRendererThreadManager.cs
- Select.cs
- Identifier.cs
- RenamedEventArgs.cs
- SHA1CryptoServiceProvider.cs
- PageAsyncTaskManager.cs
- TemplateInstanceAttribute.cs
- SizeIndependentAnimationStorage.cs
- SessionSymmetricMessageSecurityProtocolFactory.cs
- HttpListenerException.cs
- BlurEffect.cs
- MethodRental.cs
- _NestedMultipleAsyncResult.cs
- ControlValuePropertyAttribute.cs
- CanonicalFormWriter.cs
- AnimatedTypeHelpers.cs
- ArrangedElementCollection.cs
- BindingValueChangedEventArgs.cs
- AccessorTable.cs
- AnnotationDocumentPaginator.cs
- XmlException.cs
- WebColorConverter.cs
- SingleTagSectionHandler.cs
- Polyline.cs
- IisTraceWebEventProvider.cs
- validationstate.cs
- TokenFactoryCredential.cs
- COAUTHINFO.cs
- AssertValidation.cs
- WorkerRequest.cs
- RoutedEventConverter.cs
- RadioButton.cs
- DBSchemaTable.cs
- SspiNegotiationTokenAuthenticatorState.cs
- PerformanceCounterPermissionEntry.cs
- WebReferencesBuildProvider.cs
- Choices.cs
- SendParametersContent.cs
- CssClassPropertyAttribute.cs
- InternalDispatchObject.cs
- NotifyCollectionChangedEventArgs.cs
- Scripts.cs
- GcHandle.cs
- SharedConnectionInfo.cs
- BitmapEffectInputData.cs
- BaseCodePageEncoding.cs
- FixedTextPointer.cs
- SignatureToken.cs