C# 在看似无辜的WeakReference访问中使用NullReference?

C# 在看似无辜的WeakReference访问中使用NullReference?,c#,caching,weak-references,portable-class-library,C#,Caching,Weak References,Portable Class Library,我有一段使用weakreference的代码。我知道常见的.IsAlive竞争条件,所以我没有使用它。我基本上是这样的: WeakReference lastString=new WeakReference(null); public override string ToString() { if(lastString!=null) { var s=lastString.Target as string; //error here if(s!=null) {

我有一段使用weakreference的代码。我知道常见的
.IsAlive
竞争条件,所以我没有使用它。我基本上是这样的:

WeakReference lastString=new WeakReference(null);
public override string ToString()
{
  if(lastString!=null)
  {
    var s=lastString.Target as string; //error here
    if(s!=null)
    {
      return s;
    }
  }
  var str=base.ToString();
  lastString=new WeakReference(str);
  return str;
}
if(lastString!=null && limiter==null || limiter=lastLimiter)
if((lastString!=null && limiter==null) || limiter=lastLimiter)
不知怎的,我在标记行得到一个空引用异常。通过调试,我可以确认lastString确实为null,尽管它被包装在null检查中,并且lastString从未实际设置为null

这种情况也只发生在复杂的流中,这使我认为垃圾收集以某种方式获取了我的实际WeakReference对象,而不仅仅是它的目标

有人能告诉我这是怎么发生的,最好的行动方案是什么吗

编辑:
我根本无法确定这一切的原因。最后,我将错误代码包装在一个try-catch中,现在就修复它。不过我对这个问题的根本原因很感兴趣。我一直在尝试在一个简单的测试用例中重现这一点,但事实证明很难做到。此外,这仅在单元测试运行程序下运行时发生。如果我将代码精简到最低限度,它将在使用TestDriven和Gallio运行时继续崩溃,但在放入控制台应用程序时不会失败,这最终是一个很难发现的逻辑错误

令人不快的if语句实际上更像这样:

WeakReference lastString=new WeakReference(null);
public override string ToString()
{
  if(lastString!=null)
  {
    var s=lastString.Target as string; //error here
    if(s!=null)
    {
      return s;
    }
  }
  var str=base.ToString();
  lastString=new WeakReference(str);
  return str;
}
if(lastString!=null && limiter==null || limiter=lastLimiter)
if((lastString!=null && limiter==null) || limiter=lastLimiter)
真正的分组更像这样:

WeakReference lastString=new WeakReference(null);
public override string ToString()
{
  if(lastString!=null)
  {
    var s=lastString.Target as string; //error here
    if(s!=null)
    {
      return s;
    }
  }
  var str=base.ToString();
  lastString=new WeakReference(str);
  return str;
}
if(lastString!=null && limiter==null || limiter=lastLimiter)
if((lastString!=null && limiter==null) || limiter=lastLimiter)
正如墨菲定律所规定的,在这一个不相关的测试用例中,
lastLimiter
lastString
被一个方法设置为null,该方法只在这一个测试用例中使用


因此,是的,CLR中没有bug,只是我自己的逻辑bug,很难发现

这其中有任何相互阅读的问题吗?@Tigran我无法在一个独立的简单测试用例中重现这一点。它所在的程序是多线程的,但是这个特定的对象不应该一次被多个线程访问(我可以通过调试器合理地确定这一点)。这种情况是在每次执行“复杂流”时发生的,还是偶尔发生的?而且,即使它是多线程的,
lastString
也永远不会为null,并且赋值是原子的,所以这应该是线程安全的,假设base.ToString是线程safe@Cemafor每一次。我有一个单元测试,它公开了它,但不能在我们封闭的代码之外成功地复制它。同样,这在发布和调试模式下发生