Custom implementation of WeakReference

WeakReference in BCL was developed in the era of predicates, so the interface is not as good as it could be. Also, the IsAlive property is very easy to use. Looking at the implementation of the WeakReference reflector, we can implement it ourselves. Here is what I came up with:

[SecurityPermission(Flags = SecurityPermissionFlag.UnmanagedCode)] public sealed class WeakRef<T> where T : class { private readonly volatile IntPtr _ptr; public WeakRef(T target) : this(target, false) { } [SecuritySafeCritical] public WeakRef(T target, bool trackResurrection) { var handle = GCHandle.Alloc(target, trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak); _ptr = GCHandle.ToIntPtr(handle); } [SecuritySafeCritical] ~WeakRef() { var ptr = _ptr; if ((ptr != IntPtr.Zero) && (ptr == Interlocked.CompareExchange(ref _ptr, IntPtr.Zero, ptr))) { var handle = GCHandle.FromIntPtr(ptr); handle.Free(); } } public T Target { get { var ptr = _ptr; if (IntPtr.Zero != ptr) { var target = GCHandle.FromIntPtr(ptr).Target; if (_ptr != IntPtr.Zero) { return (T)target; } } return null; } } } 

but I'm not sure I got the BCL right implementation. Can anyone spot any problems in the code above?

+7
source share
2 answers

I see nothing wrong with the addition of error handling. However, I prefer this implementation for its simplicity, especially since it uses the BCL version, and you do not need to try this โ€œcorrectlyโ€:

 public sealed class WeakReference<T> where T : class { public WeakReference(T target) : this(target, trackResurrection) {} public WeakReference(T target, bool trackResurrection) { refTarget = new WeakReference(target, trackResurrection); } public T Target { get { return refTarget.Target as T; } } public bool IsAlive { get { return refTarget.IsAlive; }} private readonly WeakReference refTarget; } 
+6
source
  • GCHandle methods can throw exceptions - so make sure you have try / catches .
  • You can encourage more efficient use by providing the TryGetTarget method.
  • Why call him WeakRef ?

Here is my move.

 public sealed class WeakReference<T> : IDisposable where T : class { private volatile IntPtr _handle; private GCHandleType _handleType; public WeakReference(T target) : this(target, false) { } [SecuritySafeCritical] public WeakReference(T target, bool trackResurrection) { if (target == null) throw new ArgumentNullException("target"); _handleType = trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak; Target = target; } [SecuritySafeCritical] ~WeakReference() { Dispose(); } public void Dispose() { var ptr = _handle; if ((ptr != IntPtr.Zero) && Interlocked.CompareExchange(ref _handle, IntPtr.Zero, ptr) == ptr) { try { var handle = GCHandle.FromIntPtr(ptr); if (handle.IsAllocated) handle.Free(); } catch { } } GC.SuppressFinalize(this); } public bool TryGetTarget(out T target) { var ptr = _handle; if (ptr != IntPtr.Zero) { try { var handle = GCHandle.FromIntPtr(ptr); if (handle.IsAllocated) { target = (T)handle.Target; return !object.ReferenceEquals(target, null); } } catch { } } target = null; return false; } public bool TryGetTarget(out T target, Func<T> recreator) { IntPtr ptr = _handle; try { var handle = GCHandle.FromIntPtr(ptr); if (handle.IsAllocated) { target = (T)handle.Target; if (!object.ReferenceEquals(target, null)) return false; } } catch { } T createdValue = null; target = null; while ((ptr = _handle) == IntPtr.Zero || object.ReferenceEquals(target, null)) { createdValue = createdValue ?? recreator(); var newPointer = GCHandle.Alloc(createdValue, _handleType).AddrOfPinnedObject(); if (Interlocked.CompareExchange(ref _handle, newPointer, ptr) == ptr) { target = createdValue; return true; } else if ((ptr = _handle) != IntPtr.Zero) { try { var handle = GCHandle.FromIntPtr(ptr); if (handle.IsAllocated) { target = (T)handle.Target; if (!object.ReferenceEquals(target, null)) return false; } } catch { } } } return false; } public bool IsAlive { get { var ptr = _handle; return ptr != IntPtr.Zero && GCHandle.FromIntPtr(ptr).IsAllocated; } } public T Target { get { T target; TryGetTarget(out target); return target; } set { Dispose(); _handle = GCHandle.Alloc(value, _handleType).AddrOfPinnedObject(); GC.ReRegisterForFinalize(this); } } } 
0
source

All Articles