Как опытный программист C ++, пытающийся привыкнуть к .NET, есть деталь реализации в свойстве WeakReference от Microsoft "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);
}
}
...
}
Что меня беспокоит, так это то, почему они дважды проверяют действительность m_handle? В частности, в методе 'set' - использование GC.KeepAlive в конце метода должно предохранять WeakReference от сбора мусора и, таким образом, сохранять дескриптор ненулевым - верно?
А в случае 'get' - когда мы на самом деле получили ссылку на цель через InternalGet, зачем снова проверять исходное значение m_handle? Все, что я могу думать, - это то, что, возможно, они пытаются защититься от удаления и завершения WeakReference во время или после InternalGet - но, конечно, разве он не может быть удален и завершен до того, как мы вернемся к возврату объекта? Я просто не могу придумать правильное объяснение, почему эта двойная проверка необходима здесь ...