C# 试图了解微软';WeakReference的实现 作为一个习惯于C++的程序员,试图适应.NET,微软的弱引用“目标”属性中有一个细节,它困扰着我… 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); } } ... }

C# 试图了解微软';WeakReference的实现 作为一个习惯于C++的程序员,试图适应.NET,微软的弱引用“目标”属性中有一个细节,它困扰着我… 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); } } ... },c#,.net,thread-safety,weak-references,C#,.net,Thread Safety,Weak References,困扰我的是——为什么他们要检查两次m_句柄的有效性?特别是在“set”方法中,在方法末尾使用GC.KeepAlive应该防止WeakReference被垃圾收集,从而使句柄不为零,对吗 在“get”的情况下——一旦我们通过InternalGet实际检索到了对目标的引用,为什么还要麻烦再次检查原始的m_句柄值呢?我所能想到的是,也许他们正试图防止WeakReference在InternalGet期间或之后被处理和最终确定——但肯定的是,在我们开始返回对象之前,它不能也被处理和最终确定吗?我只是想不

困扰我的是——为什么他们要检查两次m_句柄的有效性?特别是在“set”方法中,在方法末尾使用GC.KeepAlive应该防止WeakReference被垃圾收集,从而使句柄不为零,对吗

在“get”的情况下——一旦我们通过InternalGet实际检索到了对目标的引用,为什么还要麻烦再次检查原始的m_句柄值呢?我所能想到的是,也许他们正试图防止WeakReference在InternalGet期间或之后被处理和最终确定——但肯定的是,在我们开始返回对象之前,它不能也被处理和最终确定吗?我只是想不出一个有效的解释来解释为什么这里需要进行双重检查

我所能想到的是,也许他们是在试图防范 在测试期间或之后处理和最终确定的WeakReference 内接

完全正确

但是,当然,它不能也被处理和最终确定吗 在我们开始归还物品之前


否,因为此时必须创建指向对象的强指针
InternalGet
返回一个强指针,如果存储在
oldValue
中的强指针指向该对象,那么垃圾收集器就不能再回收该对象了。

您为什么这么关心实现?这是您发布的实际Microsoft许可代码,还是Mono的?+1个好问题。在这两个访问者中似乎都没有多大意义。@Dykam阅读代码是一种极好的学习方式,而将库代码视为“魔法”是一种极好的不学习和发展迷信的方式。此外,我不愿意认为即使这段代码受版权保护,它也不属于合理使用范围。@complementdseebio,这是非常正确的,但我自己发布MS代码时会有点犹豫。调用
InternalGet
本身不会创建强指针,但不管它有什么实现。@TomislavMarkovski它实际上是这样做的,当它为
GCHandle
中引用的对象创建根时(返回值)。一旦存储了返回值(oldValue),您就有了一个根GC引用,因此对象不再符合GC的条件。谢谢!不过,我不太明白其中的逻辑。唯一可以将内部句柄归零的是终结器-因此,在调用过程中,句柄可以更改的唯一方式是,如果在调用过程中调用了WeakReference的终结器。假设我有一个“僵尸”WeakReference到这个WeakReference,所以在这个WeakReference的终结器被安排好之后,我就在这个WeakReference上调用“get”。仍然-句柄上的第二次检查可以产生差异的唯一方式是,如果在第一次检查和第二次检查之间的某个地方调用了WR的终结器。但是-在第二次检查和返回之间不能调用终结器吗?我想我看到的是,任何依赖于第二次检查操作的东西仍然是一个竞争条件——即使有第二次检查……@Kevin我知道一些弱点,但对.NET的细节了解不多。尽管如此,我认为当你说“唯一可以将内部句柄归零的东西是终结器”时,你的观点是相反的。垃圾收集器清零(并在适当时调用终结器)。垃圾收集器的设计决不会对存在活动强引用的对象执行此操作,
oldValue
在您所关注的事件序列中。