通用和非通用WeakReference之间的行为差​​异

问题描述

我发现了一般WeakReference的行为中没有想到的东西。

在我的测试中,在调用GC.Collect()之后释放了WeakReference的实例,但对于普通的WeakReference却没有:

单元测试用例

using NUnit.Framework;
using System;

namespace NUnitTestProject1
{
    public class Tests
    {
        private const bool trackResurrection = false;

        [SetUp]
        public void Setup()
        {
        }

        [TestCase(2,GCCollectionMode.Default,true)]
        public void TestWeakReferenceWithObject(int generation,GCCollectionMode forced,bool blocking)
        {
            static WeakReference CreateWeakReference()
            {
                return new WeakReference(new object(),trackResurrection);
            }

            var x = CreateWeakReference();

            Assert.IsTrue(x.IsAlive);

            GC.Collect(generation,forced,blocking);

            Assert.IsFalse(x.IsAlive);
        }

        [TestCase(2,GCCollectionMode.Forced,true)]
        public void TestWeakReferenceWithString(int generation,bool blocking)
        {
            static WeakReference CreateWeakReference()
            {
                return new WeakReference(new string('a',100),true)]
        public void TestGenericWeakReferenceWithObject(int generation,bool blocking)
        {
            static WeakReference<object> CreateWeakReference()
            {
                return new WeakReference<object>(new object(),trackResurrection);
            }

            var x = CreateWeakReference();

            Assert.IsTrue(x.TryGetTarget(out var _));

            GC.Collect(generation,blocking);

            Assert.IsFalse(x.TryGetTarget(out var _));
        }

        [TestCase(2,true)]
        public void TestGenericWeakReferenceWithString(int generation,bool blocking)
        {
            static WeakReference<string> CreateWeakReference()
            {
                return new WeakReference<string>(new string('a',blocking);

            Assert.IsFalse(x.TryGetTarget(out var _));
        }
    }
}

我已经尝试过文档:

.NET Framework参考源代码

但是我找不到导致行为不同的原因吗?

测试参数

可传递参数:

[TestCase(0,true)]
[TestCase(1,true)]
[TestCase(2,true)]
[TestCase(0,true)]

不可传递的参数:

//[TestCase(0,GCCollectionMode.Optimized,true)]
//[TestCase(1,true)]
//[TestCase(2,true)]

解决方法

仅注释掉第一个断言,我就通过了我的通用弱引用测试用例:

// Assert.IsTrue(x.TryGetTarget(out var _));

或者通过将调用移至WeakReference<T>.TryGetTarget(out T target)来实现其自身功能:

using NUnit.Framework;
using System;

namespace NUnitTestProject1
{
    public class Tests
    {
        private const bool trackResurrection = false;

        [SetUp]
        public void Setup()
        {
        }
       
        [TestCase(2,GCCollectionMode.Forced,true)]
        public void TestGenericWeakReferenceWithObject(int generation,GCCollectionMode forced,bool blocking)
        {
            static WeakReference<object> CreateWeakReference()
            {
                return new WeakReference<object>(new object(),trackResurrection);
            }

            static bool IsAlive(WeakReference<object> weakReference)
            {
                return weakReference.TryGetTarget(out var _);
            }

            var x = CreateWeakReference();

            Assert.IsTrue(IsAlive(x));            

            GC.Collect(generation,forced,blocking);

            Assert.IsFalse(IsAlive(x));
        }

        [TestCase(2,true)]
        public void TestGenericWeakReferenceWithString(int generation,bool blocking)
        {
            static WeakReference<string> CreateWeakReference()
            {
                return new WeakReference<string>(new string('a',100),trackResurrection);
            }

            static bool IsAlive(WeakReference<string> weakReference)
            {
                return weakReference.TryGetTarget(out var _);
            }

            var x = CreateWeakReference();

            Assert.IsTrue(IsAlive(x));

            GC.Collect(generation,blocking);

            Assert.IsFalse(IsAlive(x));
        }
    }
}

我的呼叫x.WeakReference(out var _)中的丢弃变量必须保留对弱引用目标的引用。 添加变量作用域不会影响测试用例,但仍然失败:

{
    x.WeakReference(out var _)
}