As a seasoned C++ programmer trying to get accustomed to .NET, there's an implementation detail in Microsoft's WeakReference "Target" property that's bugging me...
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);
}
}
...
}
The thing that's bugging me is this - why are they checking the validity of m_handle twice? Particularly in the 'set' method - the use of the GC.KeepAlive at the end of the method should keep the WeakReference from being garbage collected, and thus keep the handle non-zero - right?
And in the case of the 'get' - once we've actually retrieved a reference to the target via InternalGet, why bother checking the original m_handle value again? All I can think is that perhaps they're trying to guard against the WeakReference being disposed and finalized either during or after the InternalGet - but surely, couldn't it also be disposed and finalized before we get around to returning the object? I just can't come up w/ a valid explanation as to why this double-checking is necessary here...
A weak reference permits the garbage collector to collect the object while still allowing the application to access the object. A weak reference is valid only during the indeterminate amount of time until the object is collected when no strong references exist.
A weak reference is a way to have some pointer to an object that does have any reference (strong reference). In . NET, any normal reference to another object is a strong reference . That is, when you declare a variable of a type that is not a primitive/value type, you are declaring a strong reference.
Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed. Weak references are most often used to implement canonicalizing mappings. Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable.
Weak references are all about garbage collection. A standard object will not "disappear" until all references to it are severed, this means all the references your various objects have to it have to be removed before garbage collection will consider it garbage.
All I can think is that perhaps they're trying to guard against the WeakReference being disposed and finalized either during or after the InternalGet
That's exactly right.
but surely, couldn't it also be disposed and finalized before we get around to returning the object?
No, because at that point, a strong pointer must have been created to the object. InternalGet
returns a strong pointer, and if that strong pointer, stored in oldValue
, is to the object, now the object can no longer be reclaimed by the garbage collector.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With