Skip to content

Instantly share code, notes, and snippets.

@amwaters
Last active April 19, 2017 05:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amwaters/057d5a2f1ca85ed1d8c8162e5eda0aa3 to your computer and use it in GitHub Desktop.
Save amwaters/057d5a2f1ca85ed1d8c8162e5eda0aa3 to your computer and use it in GitHub Desktop.
Base implementation of IDisposable for .NET
// Base implementation of IDisposable for .NET
// (c) 2017 Aaron Waters, All Rights Reserved.
/* This file released under MIT license:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Carina
{
/// <summary>
/// Base implementation of IDisposable
/// </summary>
public class DisposableBase : IDisposable
{
object myLock = new object();
bool disposedValue = false;
Queue<Action> disposalActions = new Queue<Action>();
Queue<WeakReference<IDisposable>> disposables = new Queue<WeakReference<IDisposable>>();
/// <summary>
/// Disposes of this object
/// </summary>
protected virtual void Dispose(bool disposing)
{
lock (myLock)
{
if (!disposedValue)
{
disposedValue = true;
while (disposalActions.Count > 0)
{
try // could get messy!
{
disposalActions.Dequeue().Invoke();
}
catch (Exception e)
{
Debugx.Debug("Disposal error (from DisposableBase.OnDisposalTry): " + e.Message);
}
}
while (disposables.Count > 0)
{
var dispwf = disposables.Dequeue();
IDisposable disp;
if (dispwf.TryGetTarget(out disp))
disp.Dispose();
}
disposables = null;
}
}
}
/// <summary>
/// Disposes of this object
/// </summary>
public void Dispose()
{
Dispose(true);
}
/// <summary>
/// True if this object has been disposed.
/// </summary>
public bool IsDisposed
{
get { lock (myLock) { return disposedValue; } }
}
/// <summary>
/// Throws an exception if this object has been disposed.
/// </summary>
protected void AssertNotDisposed()
{
lock (myLock)
{
if (disposedValue)
throw new ObjectDisposedException("");
}
}
/// <summary>
/// Adds an object to a collection of disposables which will be disposed of during disposal.
/// The collection uses weak references.
/// </summary>
protected void EnqueDisposable(IDisposable obj)
{
lock (myLock)
{
AssertNotDisposed();
disposables.Enqueue(new WeakReference<IDisposable>(obj));
}
}
/// <summary>
/// Tries to run the provided action on disposal
/// </summary>
protected void OnDisposalTry(Action onDispose)
{
disposalActions.Enqueue(onDispose);
}
}
#if UNITY_5
// there's no support for WeakReference<T> in Unity 5!
/// <summary>
/// A drop-in replacement for .NET's strongly-typed <see cref="System.WeakReference{T}"/>.
/// Does not support ISerializable or SetTarget (as the proper .NET version does).
/// </summary>
public class WeakReference<T>
where T : class
{
/// <summary>
/// Initializes a new instance of the <see cref="WeakReference{T}"/> class that references the specified object.
/// </summary>
/// <param name="target">The object to reference, or null.</param>
public WeakReference(T target)
{
this.targetRef = new WeakReference(target);
}
/// <summary>
/// Initializes a new instance of the <see cref="WeakReference{T}"/> class that references the specified object and uses the specified resurrection tracking.
/// </summary>
/// <param name="target">The object to reference, or null.</param>
/// <param name="trackResurrection">trackResurrection: true to track the object after finalization; false to track the object only until finalization.</param>
public WeakReference(object target, bool trackResurrection)
{
this.targetRef = new WeakReference(target, trackResurrection);
}
WeakReference targetRef;
/// <summary>
/// Tries to retrieve the target object that is referecned by the current <see cref="WeakReference{T}"/>.
/// </summary>
/// <param name="target">When this method returns, contains the target object, if it is available. This parameter is treated as uninitialized.</param>
/// <returns>True if the target was retrieved; otherwise false.</returns>
public bool TryGetTarget(out T target)
{
target = null;
target = targetRef.Target as T;
return target != null;
}
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment