BCL中的WeakReference是在仿制药时代设计的,所以它的界面并不尽如人意。 IsAlive属性也很容易被误用。 查看WeakReference槽Reflector的实现,我们似乎可以自己实现它。 以下是我提出的建议:
[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对手。 任何人都可以在上面的代码中发现任何问题吗?
答案 0 :(得分:6)
除了添加错误处理之外,我没有发现任何错误。但是,我更喜欢这个实现的简单性,特别是因为它使用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;
}
答案 1 :(得分:0)
GCHandle
方法可能会引发异常 - 因此请确保您拥有try
/ catches
。TryGetTarget
方法来鼓励更好地使用。WeakRef
?这是我的目标。
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);
}
}
}