UniqueOperationExecutor - Houzkin/TreeStructures GitHub Wiki

UniqueOperationExcutor

A class to prevent recursive calls or duplicates for specified operations.

public class UniqueOperationExecutor{

    public void Register(string key, Action action){ }

    public IDisposable ExecuteUnique(string key){ }

    public IDisposable LateEvalute<TProp>(string key, Func<TProp> getPropertyValue){ }

    public IDisposable ExecuteUnique(Action operation){ }
}

Use Register to set a key and the corresponding operation.
By disposing the IDisposable returned by the method, the operation is executed when the last IDisposable is disposed.

LateEvaluate is executed only when the method is first called and when the last IDisposable is disposed, and the value of getPropertyValue is different.

In addition, the ExecuteUnique(Action operation) method is provided as a method that does not require prior registration.
There is no need to set a key; instead, it is identified by the value of operation.Method.MetadataToken.

Example

Use ExecuteUnique method.

public static void MethodG() {
    var uniExecutor = new UniqueOperationExecutor();

    var sw = new Stopwatch();
    Action displayElapsedTime = () => {
        Console.WriteLine($"Time  {sw.Elapsed.Seconds}.{sw.Elapsed.Milliseconds}(sec)");
    };
    uniExecutor.Register("keyA", displayElapsedTime);

    sw.Start();
    var t1 = Task.Run(() => {
        var exe = uniExecutor.ExecuteUnique("keyA");
        Thread.Sleep(1000);
        exe.Dispose();
    });
    var t2 = Task.Run(() => {
        Thread.Sleep(800);
        var exe = uniExecutor.ExecuteUnique("keyA");
        Thread.Sleep(800);
        exe.Dispose();
    });
    var t3 = Task.Run(() => {
        var exe = uniExecutor.ExecuteUnique("keyA");
        Thread.Sleep(500);
        exe .Dispose();
    });
    var t4 = Task.Run(() => {
        Thread.Sleep(2000);
        var exe = uniExecutor.ExecuteUnique("keyA");
        Thread .Sleep(500);
        exe .Dispose();
    });

    Task.WaitAll(t1, t2, t3, t4);
    //Time  1.621(sec)
    //Time  2.537(sec)
}

Use LateEvaluate method.

public class NoticeLevelChangedNode : ObservableGeneralTreeNode<NoticeLevelChangedNode> {
    public NoticeLevelChangedNode() {
        evaluateLevelPropValue = whetherLevelChanged;
        this.StructureChanged += (s, e) => {
            if (e.IsAncestorChanged) {
                evaluateLevelPropValue.Dispose();
                evaluateLevelPropValue = whetherLevelChanged;
            }
        };
    }
    UniqueOperationExecutor? _uniExecutor;
    UniqueOperationExecutor uniExecutor {
        get {
            if (_uniExecutor == null) {
                _uniExecutor = new UniqueOperationExecutor();
                _uniExecutor.Register(nameof(Level), () => OnPropertyChanged(nameof(Level)));
            }
            return _uniExecutor;
        }
    }
    IDisposable evaluateLevelPropValue;
    IDisposable whetherLevelChanged => uniExecutor.LateEvaluate(nameof(Level), () => this.Level);
    public int Level => this.Depth();
}

or

public class NoticeDepthChangedNode : ObservableGeneralTreeNode<NoticeDepthChangedNode> {
    public NoticeDepthChangedNode() {
        //initialize instance
        var uniExectr = new UniqueOperationExecutor();
        //register action with key.
        uniExectr.Register(nameof(Level), () => OnPropertyChanged(nameof(this.Level)));

        //set initial status
        evaluateLevel = uniExectr.LateEvaluate(nameof(Level), () => Level);
        this.StructureChanged += (s, e) => {
            if (e.IsAncestorChanged) { 
                //evaluate whether level changed
                evaluateLevel.Dispose();
                //reset status
                evaluateLevel = uniExectr.LateEvaluate(nameof(Level), () => Level);
            }
        };
    }
    IDisposable evaluateLevel;
    public int Level => this.Depth();
}

source code

StructureChangedEventExecutor

An object responsible for notifying changes in the tree structure.

public sealed class StructureChangedEventExecutor<TNode> : UniqueOperationExecutor
where TNode : class, IObservableTreeNode<TNode>{

    public StructureChangedEventExecutor(TNode node){ }

    public IDisposable LateEvaluateTree(){ }

}

LateEvaluateTree, like LateEvaluate, issues change notifications when the tree structure changes, but only when it is first called and when the last IDisposable is disposed.

Where used

ObservableGeneralTreeNode

⚠️ **GitHub.com Fallback** ⚠️