UniqueOperationExecutor_ja - Houzkin/TreeStructures GitHub Wiki

UniqueOperationExcutor

指定した処理の再帰的な呼び出し、或いは重複を防止するためのクラスです。

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){ }
}

Registerでキーとそれに対応する処理を設定します。
メソッドの戻り値であるIDisposableをDisposeすることで、最後のIDisposableが破棄された時に処理が実行されます。

LateEvaluateは最初に呼び出された時と、最後のIDisposableが破棄されたときで、getPropertyValueの値が異なっていた場合のみ実行されます。

また、事前に登録が不要なメソッドとしてExecuteUnique(Action operation)メソッドも用意しています。
キーの設定は必要ありませんが、代わりにoperation.Method.MetadataTokenの値によって判別します。

Example

ExecuteUniqueメソッドを使用

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)
}

LateEvaluateメソッドを使用

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), () => 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

ツリー構造の変更通知を担うオブジェクトです。

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

    public StructureChangedEventExecutor(TNode node){ }

    public IDisposable LateEvaluateTree(){ }

}

LateEvaluateTreeは、LateEvaluateと同様、最初に呼び出された時と最後のIDisposableが破棄された時でツリーの構造が変化していた場合に変更通知を発行します。

使用箇所

ObservableGeneralTreeNode

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