试图了解微软的WeakReference实现

Kev*_*vin 10 .net c# weak-references thread-safety

作为一名经验丰富的C++程序员试图习惯于.NET,微软的WeakReference"Target"属性中有一个实现细节,这让我很烦恼......

public class WeakReference : ISerializable
{
    internal IntPtr m_handle;
    internal bool m_IsLongReference;
                 ...
    public virtual object Target
    {
        [SecuritySafeCritical]
        get
        {
            IntPtr handle = this.m_handle;
            if (IntPtr.Zero == handle)
            {
                return null;
            }
            object result = GCHandle.InternalGet(handle);
            if (!(this.m_handle == IntPtr.Zero))
            {
                return result;
            }
            return null;
        }
        [SecuritySafeCritical]
        set
        {
            IntPtr handle = this.m_handle;
            if (handle == IntPtr.Zero)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
            }
            object oldValue = GCHandle.InternalGet(handle);
            handle = this.m_handle;
            if (handle == IntPtr.Zero)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
            }
            GCHandle.InternalCompareExchange(handle, value, oldValue, false);
            GC.KeepAlive(this);
        }
    }
     ...
       }
Run Code Online (Sandbox Code Playgroud)

困扰我的是这个 - 为什么他们两次检查m_handle的有效性?特别是在'set'方法中 - 在方法结束时使用GC.KeepAlive应该保持WeakReference不被垃圾收集,从而使句柄保持非零 - 对吗?

在'get'的情况下 - 一旦我们通过InternalGet实际检索了对目标的引用,为什么还要再次检查原始的m_handle值呢?我可以想到的是,或许他们正试图防止WeakReference在InternalGet期间或之后被处理和最终确定 - 但是当然,在我们到处返回对象之前,它是否也不能被处理和最终确定?我只是不能提出一个有效的解释,为什么这里需要进行双重检查......

Pas*_*uoq 8

我所能想到的可能是他们试图防止在InternalGet期间或之后处理和最终确定WeakReference

这是完全正确的.

但可以肯定的是,在我们回到对象之前,它是否也不能被处理和最终确定?

不,因为在那时,必须已经为对象创建了一个强指针.InternalGet返回一个强指针,如果该指针存储在oldValue该对象中,那么垃圾收集器现在无法再回收该对象.