簡體   English   中英

自定義弱引用實現

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM