I discovered something I did not expect in the behavior of generic WeakReference.
In my test, the instance of WeakReference are freed after a GC.Collect() call but not for generic WeakReference:
Unit test case
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, GCCollectionMode forced, bool blocking)
{
static WeakReference CreateWeakReference()
{
return new WeakReference(new string('a', 100), trackResurrection);
}
var x = CreateWeakReference();
Assert.IsTrue(x.IsAlive);
GC.Collect(generation, forced, blocking);
Assert.IsFalse(x.IsAlive);
}
[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);
}
var x = CreateWeakReference();
Assert.IsTrue(x.TryGetTarget(out var _));
GC.Collect(generation, forced, blocking);
Assert.IsFalse(x.TryGetTarget(out var _));
}
[TestCase(2, GCCollectionMode.Forced, true)]
public void TestGenericWeakReferenceWithString(int generation, GCCollectionMode forced, bool blocking)
{
static WeakReference<string> CreateWeakReference()
{
return new WeakReference<string>(new string('a', 100), trackResurrection);
}
var x = CreateWeakReference();
Assert.IsTrue(x.TryGetTarget(out var _));
GC.Collect(generation, forced, blocking);
Assert.IsFalse(x.TryGetTarget(out var _));
}
}
}
I have tried the documentation:
And the .NET Framework reference source code:
But I can't find a reason to the different behave?
Test parameters
Passable parameters:
[TestCase(0, GCCollectionMode.Default, true)]
[TestCase(1, GCCollectionMode.Default, true)]
[TestCase(2, GCCollectionMode.Default, true)]
[TestCase(0, GCCollectionMode.Forced, true)]
[TestCase(1, GCCollectionMode.Forced, true)]
[TestCase(2, GCCollectionMode.Forced, true)]
Not passable parameters:
//[TestCase(0, GCCollectionMode.Optimized, true)]
//[TestCase(1, GCCollectionMode.Optimized, true)]
//[TestCase(2, GCCollectionMode.Optimized, true)]