예제 #1
0
 /// <summary>
 /// Throw an exception if the given object isn't already registered.
 /// </summary>
 /// <param name="obj">The object to look for.</param>
 private void CheckObjectIsNotRegistered(IManagedDisposableObject obj)
 {
     if (this.dependencies.ContainsKey(obj.Id))
     {
         throw new InvalidOperationException("Object is already registered");
     }
 }
예제 #2
0
            /// <summary>
            /// Called when a managed disposable object is about to be disposed. This methods
            /// disposes all dependent ojects.
            /// </summary>
            /// <param name="obj">The object being disposed.</param>
            private void OnObjectDispose(IManagedDisposableObject obj)
            {
                // Remove the object callback so that this method isn't called twice
                obj.Disposed -= this.OnObjectDispose;

                lock (this.lockObject)
                {
                    // During process shutdown and AppDomain unloading objects in the
                    // RegisteredForFinalization queue are finalized even though they are still
                    // reachable. This means the objects can be finalized in an unexpected
                    // fashion. To deal with that we ignore these callbacks during shutdown
                    // and AppDomain unload.
                    //
                    // An object can be finalized/disposed multiple times. We have to make
                    // sure this object is still registered.
                    if (!AppDomain.CurrentDomain.IsFinalizingForUnload() &&
                        !Environment.HasShutdownStarted &&
                        !this.wasDisposed &&
                        !this.wasFinalized &&
                        this.dependencies.ContainsKey(obj.Id))
                    {
                        this.DisposeDependents(obj);
                        this.Unregister(obj);
                    }
                }
            }
        private static void VerifyIManagedDisposableObjectDisposePassesSelfToEvent(IManagedDisposableObject obj)
        {
            IManagedDisposableObject arg = null;

            obj.Disposed += x => arg = x;
            obj.Dispose();
            Assert.AreEqual(obj, arg);
        }
        private static void VerifyIManagedDisposableObjectDisposeFiresEvent(IManagedDisposableObject obj)
        {
            bool eventFired = false;

            obj.Disposed += ignored => eventFired = true;
            obj.Dispose();
            Assert.IsTrue(eventFired);
        }
예제 #5
0
 /// <summary>
 /// Call the dispose method of the specified object.
 /// </summary>
 /// <param name="obj">The object to dispose.</param>
 private void DisposeObject(IManagedDisposableObject obj)
 {
     // Recursively dispose all dependent objects, deregister
     // (to avoid the Disposed event) then dispose.
     this.DisposeDependents(obj);
     this.Unregister(obj);
     obj.Dispose();
 }
예제 #6
0
 /// <summary>
 /// Unregister an object. The object must have been registered with
 /// this manager.
 /// </summary>
 /// <param name="obj">The object to remove the registration for.</param>
 private void Unregister(IManagedDisposableObject obj)
 {
     lock (this.lockObject)
     {
         this.CheckObjectIsRegistered(obj);
         this.RemoveEntriesFor(obj.Id);
         this.CheckObjectIsNotRegistered(obj);
     }
 }
예제 #7
0
 /// <summary>
 /// Register a new managed disposable object. This object isn't dependent
 /// on anything, but can be depended on.
 /// </summary>
 /// <param name="obj">The object to register.</param>
 public void Register(IManagedDisposableObject obj)
 {
     lock (this.lockObject)
     {
         this.CheckObjectIsNotRegistered(obj);
         this.RegisterAsDependent(obj, this);
         this.CheckObjectIsRegistered(obj);
     }
 }
예제 #8
0
            /// <summary>
            /// Remove all dependencies/dependentOn entries for the given id.
            /// </summary>
            /// <param name="objectId">The id to remove entries for.</param>
            private void RemoveEntriesFor(DisposableObjectId objectId)
            {
                // Remove the object from the list of its parent's dependencies
                IManagedDisposableObject parent = this.dependentOn[objectId];

                this.dependencies[parent.Id].RemoveReferenceTo(objectId);
                this.dependentOn.Remove(objectId);

                // Delete the list of dependencies for this object
                this.dependencies.Remove(objectId);
            }
예제 #9
0
            /// <summary>
            /// Call the dispose method of all dependent objects.
            /// </summary>
            /// <param name="obj">
            /// The depended on object. This object will not be disposed, but its
            /// dependents will be.
            /// </param>
            private void DisposeDependents(IManagedDisposableObject obj)
            {
                // Disposing an object removes it from the list. To avoid trying to iterate a list
                // that is being modified, we copy the list first.
                var referencesToDispose = new WeakReferenceCollection(this.dependencies[obj.Id]);

                foreach (WeakReferenceOf <IManagedDisposableObject> reference in referencesToDispose)
                {
                    IManagedDisposableObject objectToDispose = reference.Target;
                    if (null != objectToDispose)
                    {
                        this.DisposeObject(objectToDispose);
                    }
                    else
                    {
                        // The weak reference can't be resolved. Remove all entries.
                        this.dependencies[obj.Id].RemoveReferenceTo(reference.Id);
                        this.RemoveEntriesFor(reference.Id);
                    }
                }
            }
예제 #10
0
            /// <summary>
            /// Register an object as dependent on another object. If the depended-on object is
            /// disposed then the registered object will be disposed too.
            /// </summary>
            /// <param name="child">The object to register.</param>
            /// <param name="parent">
            /// The depended on object. This object must have been registered already.
            /// </param>
            public void RegisterAsDependent(IManagedDisposableObject child, IManagedDisposableObject parent)
            {
                lock (this.lockObject)
                {
                    this.CheckObjectIsNotRegistered(child);
                    this.CheckObjectIsRegistered(parent);

                    // Add the child to the list of the parent's dependents
                    this.dependencies[parent.Id].Add(new WeakReferenceOf <IManagedDisposableObject>(child));

                    // A child starts out with no dependents
                    this.dependencies[child.Id] = new WeakReferenceCollection();

                    // The child is dependent on the parent
                    this.dependentOn[child.Id] = parent;

                    // We need to know when the child is disposed
                    child.Disposed += this.OnObjectDispose;

                    this.CheckObjectIsRegistered(child);
                }
            }
        private static void VerifyIManagedDisposableObjectDisposePassesSelfToEvent(IManagedDisposableObject obj)
        {
            IManagedDisposableObject arg = null;

            obj.Disposed += x => arg = x;
            obj.Dispose();
            Assert.AreEqual(obj, arg);
        }
        private static void VerifyIManagedDisposableObjectDisposeFiresEvent(IManagedDisposableObject obj)
        {
            bool eventFired = false;

            obj.Disposed += ignored => eventFired = true;
            obj.Dispose();
            Assert.IsTrue(eventFired);
        }