SoftReference<T>
public sealed class SoftReference<T> : IOptionMonad<T>, ISupplier<object>, IFunctional<Func<object>>
Represents a form of weak reference
which is eligible for garbage collection in Generation 2 only.
using DotNext.Runtime.CompilerServices;
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Threading;
namespace DotNext.Runtime
{
[System.Runtime.CompilerServices.NullableContext(2)]
[System.Runtime.CompilerServices.Nullable(0)]
[DebuggerDisplay("State = {State}")]
public sealed class SoftReference<[System.Runtime.CompilerServices.Nullable(1)] T> : IOptionMonad<T>, ISupplier<object>, IFunctional<Func<object>> where T : class
{
private sealed class Tracker : IGCCallback
{
private readonly SoftReferenceOptions options;
private readonly SoftReference<T> parent;
internal Tracker(SoftReference<T> parent, SoftReferenceOptions options)
{
this.options = options;
this.parent = parent;
}
~Tracker()
{
T strongRef = parent.strongRef;
GCIntermediateReference trackerRef = parent.trackerRef;
if (strongRef != null && trackerRef != null) {
if (this != trackerRef.Target || !options.KeepTracking(strongRef))
try {
trackerRef.Target = strongRef;
} catch (InvalidOperationException) {
} finally {
parent.strongRef = null;
}
else
GC.ReRegisterForFinalize(this);
}
}
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private volatile T strongRef;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private volatile GCIntermediateReference trackerRef;
[System.Runtime.CompilerServices.Nullable(new byte[] {
0,
2
})]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public (T Target, SoftReferenceState State) TargetAndState {
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
2
})]
get {
T val = strongRef;
SoftReferenceState item;
if (val != null)
item = SoftReferenceState.Strong;
else {
val = (trackerRef?.Target as T);
item = ((val != null) ? SoftReferenceState.Weak : SoftReferenceState.Empty);
}
return (val, item);
}
}
[ExcludeFromCodeCoverage]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private SoftReferenceState State {
get {
return TargetAndState.State;
}
}
private T Target => strongRef ?? (trackerRef?.Target as T);
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
bool IOptionMonad<T>.HasValue {
get {
return Target != null;
}
}
public SoftReference(T target, SoftReferenceOptions options = null)
{
if (target != null) {
if (options == null)
options = SoftReferenceOptions.Default;
if (options.KeepTracking(target)) {
strongRef = target;
Tracker obj = new Tracker(this, options);
trackerRef = new GCIntermediateReference(obj);
GC.KeepAlive(obj);
} else
trackerRef = new GCIntermediateReference(target);
}
}
private void ClearCore()
{
Interlocked.Exchange<GCIntermediateReference>(ref trackerRef, (GCIntermediateReference)null)?.Clear();
strongRef = null;
}
public void Clear()
{
ClearCore();
GC.SuppressFinalize(this);
}
public bool TryGetTarget([NotNullWhen(true)] out T target)
{
return (target = Target) != null;
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public Optional<T> TryGetTarget()
{
return new Optional<T>(Target);
}
[return: NotNullIfNotNull("defaultValue")]
T IOptionMonad<T>.Or(T defaultValue)
{
return Target ?? defaultValue;
}
T IOptionMonad<T>.OrDefault()
{ get; }
T IOptionMonad<T>.OrInvoke(Func<T> defaultFunc)
{
return Target ?? defaultFunc();
}
bool IOptionMonad<T>.TryGet([NotNullWhen(true)] out T target)
{
return TryGetTarget(out target);
}
object ISupplier<object>.Invoke()
{ get; }
public override string ToString()
{
return Target?.ToString();
}
public static explicit operator T([System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})] SoftReference<T> reference)
{
if (reference == null)
return null;
return reference.Target;
}
public static explicit operator Optional<T>([System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})] SoftReference<T> reference)
{
return reference?.TryGetTarget() ?? Optional<T>.None;
}
~SoftReference()
{
ClearCore();
}
}
}