< Summary

Information
Class: MyNet.Messaging.WeakCallable<T>
Assembly: MyNet.Messaging
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Messaging/WeakCallable.cs
Tag: 323_28699572109
Line coverage
86%
Covered lines: 40
Uncovered lines: 6
Coverable lines: 46
Total lines: 154
Line coverage: 86.9%
Branch coverage
60%
Covered branches: 30
Total branches: 50
Branch coverage: 60%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)66.66%6691.66%
.ctor(...)100%11100%
get_IsStatic()100%11100%
get_MethodName()33.33%66100%
get_IsAlive()68.75%171685.71%
get_Target()0%620%
get_DelegateTarget()50%44100%
MarkForDeletion()100%11100%
Execute(...)75%9876.92%
GetDelegate()62.5%88100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Messaging/WeakCallable.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="WeakCallable.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Reflection;
 9
 10namespace MyNet.Messaging;
 11
 12/// <summary>
 13/// Base class that stores a delegate (Action or Func) without creating a hard reference
 14/// to the target object. The target can be garbage collected at any time.
 15/// Consolidates common logic for both WeakAction and WeakFunc.
 16/// </summary>
 17internal abstract class WeakCallable
 18{
 19    /// <summary>
 20    /// Gets a value indicating whether the callable is static or not.
 21    /// </summary>
 22    public abstract bool IsStatic { get; }
 23
 24    /// <summary>
 25    /// Gets the name of the method that this callable represents.
 26    /// </summary>
 27    public abstract string? MethodName { get; }
 28
 29    /// <summary>
 30    /// Gets a value indicating whether the callable's target is still alive.
 31    /// </summary>
 32    public abstract bool IsAlive { get; }
 33
 34    /// <summary>
 35    /// Gets the target object. This object is stored as a WeakReference.
 36    /// </summary>
 37    public abstract object? Target { get; }
 38
 39    /// <summary>
 40    /// Marks this callable for deletion. All references are cleared.
 41    /// </summary>
 42    public abstract void MarkForDeletion();
 43}
 44
 45/// <summary>
 46/// Stores an Action or Func without creating a hard reference to the target object.
 47/// The target can be garbage collected at any time.
 48/// </summary>
 49/// <typeparam name="TDelegate">The type of the delegate (Action or Func).</typeparam>
 50internal sealed class WeakCallable<TDelegate> : WeakCallable
 51    where TDelegate : Delegate
 52{
 53    private TDelegate? _staticDelegate;
 54    private WeakReference? _targetReference;
 55    private WeakReference? _delegateTargetReference;
 56    private object? _liveReference;
 57    private MethodInfo? _method;
 1858    private bool _isAlive = true;
 59
 60    public WeakCallable(TDelegate @delegate, bool keepTargetAlive = false)
 1261        : this(@delegate.Target, @delegate, keepTargetAlive)
 62    {
 1263    }
 64
 1865    public WeakCallable(object? target, TDelegate @delegate, bool keepTargetAlive = false)
 66    {
 1867        if (@delegate.Method.IsStatic)
 68        {
 1269            _staticDelegate = @delegate;
 1270            if (target != null)
 071                _targetReference = new(target);
 1272            return;
 73        }
 74
 675        _method = @delegate.Method;
 676        _delegateTargetReference = new(@delegate.Target);
 677        _liveReference = keepTargetAlive ? @delegate.Target : null;
 678        _targetReference = new(target);
 679    }
 80
 681    public override bool IsStatic => _staticDelegate != null;
 82
 83    public override string? MethodName =>
 384        _staticDelegate?.Method.Name ?? _method?.Name;
 85
 86    public override bool IsAlive
 87    {
 88        get
 89        {
 2490            if (!_isAlive)
 691                return false;
 92
 1893            if (_staticDelegate == null && _targetReference == null && _liveReference == null)
 094                return false;
 95
 1896            if (_staticDelegate != null)
 1297                return _targetReference?.IsAlive != false;
 98
 99            // Non-static delegate
 6100            return _liveReference != null || _targetReference is { IsAlive: true };
 101        }
 102    }
 103
 0104    public override object? Target => _targetReference?.Target;
 105
 6106    private object? DelegateTarget => _liveReference ?? _delegateTargetReference?.Target;
 107
 108    public override void MarkForDeletion()
 109    {
 3110        _isAlive = false;
 3111        _targetReference = null;
 3112        _delegateTargetReference = null;
 3113        _liveReference = null;
 3114        _method = null;
 3115        _staticDelegate = null;
 3116    }
 117
 118    /// <summary>
 119    /// Executes the delegate with reflection if it's still alive.
 120    /// </summary>
 121    public object? Execute(params object?[] parameters)
 122    {
 12123        if (!IsAlive)
 3124            return null;
 125
 9126        if (_staticDelegate != null)
 127        {
 128            try
 129            {
 6130                return _staticDelegate.DynamicInvoke(parameters);
 131            }
 3132            catch
 133            {
 3134                return null;
 135            }
 136        }
 137
 3138        var target = DelegateTarget;
 3139        if (_method == null || target == null)
 0140            return null;
 141
 142        try
 143        {
 3144            return _method.Invoke(target, parameters);
 145        }
 0146        catch
 147        {
 0148            return null;
 149        }
 9150    }
 151
 6152    public TDelegate? GetDelegate() => !IsAlive || (_staticDelegate == null && (_method == null || DelegateTarget == nul
 153}
 154