DotNext by Roman Sakno

<PackageReference Include="DotNext" Version="2.10.1" />

 AtomicReference<T>

public struct AtomicReference<T> : IEquatable<T>, ISerializable
Provides container with atomic operations for the reference type.
using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Threading; namespace DotNext.Threading { [Serializable] [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public struct AtomicReference<[System.Runtime.CompilerServices.Nullable(2)] T> : IEquatable<T>, ISerializable where T : class { private const string ValueSerData = "Value"; private T value; public T Value { [MethodImpl(MethodImplOptions.AggressiveInlining)] [IsReadOnly] [return: MaybeNull] get { return Volatile.Read<T>(ref Unsafe.AsRef<T>(ref value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Volatile.Write<T>(ref this.value, value); } } public AtomicReference(T value) { this.value = value; } private AtomicReference(SerializationInfo info, StreamingContext context) { value = (T)info.GetValue("Value", typeof(T)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public T CompareExchange(T expected, T update) { return Interlocked.CompareExchange<T>(ref value, update, expected); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool CompareAndSet(T expected, T update) { return AtomicReference.CompareAndSet<T>(ref value, expected, update); } [IsReadOnly] public override string ToString() { return Value?.ToString() ?? "NULL"; } [IsReadOnly] public bool Equals([AllowNull] T other) { return object.Equals(other, Value); } [IsReadOnly] [System.Runtime.CompilerServices.NullableContext(2)] public override bool Equals(object other) { if (!(other is AtomicReference<T>)) return object.Equals(other, Value); return Equals(((AtomicReference<T>)other).Value); } [IsReadOnly] public override int GetHashCode() { return Value?.GetHashCode() ?? 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public T GetAndSet(T update) { return Interlocked.Exchange<T>(ref value, update); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [return: NotNullIfNotNull("update")] public T SetAndGet(T update) { Value = update; return update; } public T AccumulateAndGet(T x, Func<T, T, T> accumulator) { return AtomicReference.AccumulateAndGet<T>(ref value, x, accumulator); } public T AccumulateAndGet(T x, [In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 1, 1 })] ref ValueFunc<T, T, T> accumulator) { return AtomicReference.AccumulateAndGet<T>(ref value, x, ref accumulator); } public T GetAndAccumulate(T x, Func<T, T, T> accumulator) { return AtomicReference.GetAndAccumulate<T>(ref value, x, accumulator); } public T GetAndAccumulate(T x, [In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 1, 1 })] ref ValueFunc<T, T, T> accumulator) { return AtomicReference.GetAndAccumulate<T>(ref value, x, ref accumulator); } public T UpdateAndGet(Func<T, T> updater) { return AtomicReference.UpdateAndGet<T>(ref value, updater); } public T UpdateAndGet([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 1 })] ref ValueFunc<T, T> updater) { return AtomicReference.UpdateAndGet<T>(ref value, ref updater); } public T GetAndUpdate(Func<T, T> updater) { return AtomicReference.GetAndUpdate<T>(ref value, updater); } public T GetAndUpdate([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 1 })] ref ValueFunc<T, T> updater) { return AtomicReference.GetAndUpdate<T>(ref value, ref updater); } [return: NotNull] public T SetIfNull<TDerived>() where TDerived : T, new { T val = this.Value; if (val == null) { val = (T)(object)new TDerived(); return this.CompareExchange((T)null, val) ?? val; } return val; } public T SetIfNull(Func<T> supplier) { T val = Value; if (val == null) { val = supplier(); return CompareExchange(null, val) ?? val; } return val; } [IsReadOnly] void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Value", value, typeof(T)); } } }