tmori3y2のブログ

主にWindowsのプログラムなど

ReactivePropertyのCountNotifierを再入防止に使用する

blog.okazuki.jp

ReactiveProperty/CountNotifier.cs at master · runceel/ReactiveProperty · GitHub

「特徴的なのは、IncrementメソッドとDecrementメソッドが返すIDisposableをDisposeすることで、インクリメントやデクリメントの逆が実行されて値がもとに戻ります。」

ということは、usingが使えるので私の作ったReentrantBlockerの代わりに使えるということ・・・

tmori3y2.hatenablog.com

のコードを例に採ると・・・

private CountNotifier blocker = new CountNotifier(1);

Points
    .ObserveAddChangedItems()
    .Subscribe(vms =>
    {
        vms.ToList()
        .ForEach(vm =>
        {
            vm.X
            .SetValidateNotifyError(s =>
            {
                NumberStyles style = NumberStyles.Number & ~NumberStyles.AllowTrailingSign;
                IFormatProvider provider = CultureInfo.CurrentUICulture;

                decimal input = decimal.Zero;
                if (!decimal.TryParse(s, style, provider, out input))
                {
                    return null;
                }

                var list = model.Points
                    .Select((p, i) =>
                    {
                        decimal value = decimal.Zero;
                        if (Points[i] == vm)
                        {
                            return input;
                        }
                        if (Points[i].X.HasErrors && decimal.TryParse(Points[i].X.Value, style, provider, out value))
                        {
                            return value;
                        }
                        else
                        {
                            return p.X.Value;
                        }
                    })
                    .ToList();

                var count = list
                    .Where(x => x == input)
                    .Count();

                if (count > 1)
                {
                    return "Cannot set the duplicate X.";
                }
                else if (blocker.Count == 0)
                {
                    using (blocker.Increment())
                    {
                        Points
                            .Where(p =>
                                p.X.HasErrors && (p != vm))
                            .ToList()
                            .ForEach(p =>
                                p.X.ForceNotify());
                    }
                }
                return null;
            });
        });
    })
    .AddTo(disposables);

ただ、

  • ReentrantBlockerはIDisposableを実装しているけどDispose不要
  • CountNotifierはDispose必要
  • ReentrantBlockerの方が軽量

なので微妙だが、独自のクラスを作りたくないなら、こういう使い方も出来る。