[英]Custom WeakReference implementation
BCL 中的 WeakReference 是在 generics 時代之前設計的,所以它的界面沒有想象中那么好。 IsAlive 屬性也很容易被濫用。 通過 Reflector 查看 WeakReference 的實現,似乎我們可以自己實現它。 這是我想出的:
[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;
}
}
}
但我不確定我是否正確實施了 BCL 對應項。 任何人都可以在上面的代碼中發現任何問題嗎?
除了添加錯誤處理之外,我沒有發現任何錯誤。 然而,我更喜歡這個實現,因為它簡單,特別是因為它使用 BCL 版本,你不必努力“把它做好”:
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;
}
GCHandle
方法可能會拋出異常——所以請確保您有try
/ catches
。TryGetTarget
方法來鼓勵更好的使用。WeakRef
?這是我的 go。
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);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.