C# 如何以安全的方式获得弱引用的目标

C# 如何以安全的方式获得弱引用的目标,c#,.net,garbage-collection,weak-references,C#,.net,Garbage Collection,Weak References,考虑以下代码: var weakRef = new WeakReference(new StringBuilder("Mehran")); if (weakRef.IsAlive) { // Garbage Collection might happen. Console.WriteLine((weakRef.Target as StringBuilder).ToString()); } 在检查weakRef.IsAlive之后和使用weakRef.Target之前,可以运行G

考虑以下代码:

var weakRef = new WeakReference(new StringBuilder("Mehran"));
if (weakRef.IsAlive)
{
    // Garbage Collection might happen.
    Console.WriteLine((weakRef.Target as StringBuilder).ToString());
}
在检查
weakRef.IsAlive
之后和使用
weakRef.Target
之前,可以运行
GC.Collect

我错了吗?如果可能的话,有安全的方法吗


例如,像
weakRef.getTargetifiSisaLive()这样的API是合适的。

该API已经存在<如果对象已被垃圾收集,则code>weakRef.Target
返回
null

StringBuilder sb = weakRef.Target as StringBuilder;
if (sb != null)
{
    Console.WriteLine(sb.ToString());
}

获取目标的本地副本并检查null

WeakReference.Target
将返回
null
如果目标已收集,但您担心的是它是在您的
之间收集的。IsAlive
检查并获取目标

var weakRef = new WeakReference(new StringBuilder("Mehran"));

if (weakRef.IsAlive)
{
    var stringBuilder = weakRef.Target as StringBuilder;

    if (stringBuilder != null)
    {
        Console.WriteLine(stringBuilder.ToString());
    }
}

Console.WriteLine((weakRef.Target作为StringBuilder.ToString())将抛出空引用异常。

IsAlive属性的存在并不是为了让代码在目标处于活动状态时使用它,而是为了让代码知道目标是否已死亡,但无论如何都不想访问它。如果代码要针对null测试
Target
,这将导致
Target
暂时具有一个强根引用(针对null测试的代码),并且生成这样一个根引用的行为可能会阻止对象在本来应该被垃圾收集时被垃圾收集。如果代码对
Target
不感兴趣,只是为了确定它是否已经失效,那么代码没有理由获取引用。它可以简单地测试
IsAlive
,如果返回
false

,我相信你要找的是
TryGetValue
。您的代码应该如下所示:

var weakRef = new WeakReference(new StringBuilder("Mehran"));
if (weakRef.TryGetValue(out StringBuilder sb)
{
    Console.WriteLine(sb.ToString());
}

签出您应该首先强制转换为强引用,然后检查
null
。你无法保证你的强引用不会事先为空。我想知道为什么
IsAlive
存在。这是一个非常聪明的答案,谢谢。@mehrandvd:不难想象并发GC从
WeakReference
获取
目标的行为会阻止该对象在下一个周期中被收集,即使引用立即被丢弃。在这样一个系统中,当一个对象不再需要并使用
Target
而不是
IsAlive
时,想要立即采取一些行动的代码可能最终会使所讨论的对象永远活着。我想知道为什么需要检查
weakRef.IsAlive
,@supercat回答了这个问题,所以我认为检查它是没有必要的。@mehrandvd它可能没有必要,我只是在这个例子中使用它,因为它是基于您最初的问题。使用它不会造成任何伤害,但如果
为true
值意味着要检索目标是无意义的,那么它可能是一个无意义的检查,因为
as
强制转换和
上的null检查。Target
@TrevorPilley:在
WeakReference
上使用
IsAlive
。对于某些垃圾收集器,可能使用
if(wr1.IsAlive&&wr2.IsAlive&&wr3.IsAlive){Foo wt1=wr1.Target作为Foo,wt2=wr2.Target作为Foo,wt3=wr3.Target作为Foo;if(wr1!=null&&wr2!=null&&wr3!=null){…使用所有三件事…}
如果并发垃圾收集器通过跟踪自上次GC以来是否创建了对某个对象的引用来工作,则可能会有所帮助。在这种GC上,如果wr3已死亡,但wr1和wr2仍存活。。。