UniqueOperationExecutor_ja - Houzkin/TreeStructures GitHub Wiki
指定した処理の再帰的な呼び出し、或いは重複を防止するためのクラスです。
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の値によって判別します。
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();
}ツリー構造の変更通知を担うオブジェクトです。
public sealed class StructureChangedEventExecutor<TNode> : UniqueOperationExecutor
where TNode : class, IObservableTreeNode<TNode>{
public StructureChangedEventExecutor(TNode node){ }
public IDisposable LateEvaluateTree(){ }
}LateEvaluateTreeは、LateEvaluateと同様、最初に呼び出された時と最後のIDisposableが破棄された時でツリーの構造が変化していた場合に変更通知を発行します。