2

クラスにいくつかのイベントがあるとします。

 class SomeClass{
     event ChangedEventHandler SomeDoubleChanged;
     double SomeDouble;
 }

と:

 delegate void ChangedEventHandler(double d);

ここで、SomeDouble の変更イベントをリッスンしたいが、より大きな変更のみをトリガーしたいとしますdelta。今、私は次のようなことができます

 SomeObject.SomeDoubleChanged += (d) => {if(abs(d-old_d) > delta){
                                  //do something     
                                 };

しかし、私は自分のイベントでこれを処理したいので、最良の場合、次のようなことをしたいです:

 SomeObject.SomeDoubleChange += (delta, (d) => {});

それでも許可します:

 SomeObject.SomeDoubleChange += (d) => {};

これを実装する唯一の方法は、イベント キーワード全体を削除し、指定されたデリゲートで動作する += および -= 演算子を含むコンテナーを実装することです。しかし、私の意見では、これは SomeClass のユーザーに SomeDoubleChanged がイベントではないという考えを与えるため、あまり洗練された解決策ではありません。

この問題に対する最もエレガントな解決策は何でしょうか?

4

3 に答える 3

5

(ラムダ式も使用していることを考えると、ここでは「ラムダ」という用語を使用しないことをお勧めします。変更、つまりデルタに興味があるようです。)

独自の静的メソッドを作成して、適切なデリゲートを作成できます。

public static ChangedEventHandler FilterByDelta(double delta,
                                                ChangedEventHandler handler)
{
    double previous = double.MinValue;
    return d =>
    {            
        if (d - previous > delta)
        {
            handler(d);
        }
        // Possibly put this in the "if" block? Depends on what you want.
        previous = d;
    };
}

次に、次を使用できます。

SomeObject.SomeDoubleChange += Helper.FilterByDelta(5, d => ...);

残念ながら、ラムダ式で拡張メソッドを使用することはできません。これにより、これが簡単になります。

于 2013-01-21T12:38:20.597 に答える
1

このようなものを書くことができます

SomeObject.SomeDoubleChange += (d) => DoWork(lambda, d, (d) => {});

private void DoWork(double minLambda, double currentValue, ChangedEventHandler handler)
{
  if(abs(currentValue - oldValue) > minLambda))
  {
     handler(currentValue);
  }
}
于 2013-01-21T12:38:40.127 に答える
0

私のお気に入りの「エレガントな」方法は、特にReactive Extensionsの助けを借りて実装された、イベントの代わりにオブザーバブルを使用することです。そうすることができると想像してください:

class SomeClass
{
    public ObservableProperty<double> SomeDouble { get; private set; }
    public SomeClass()
    {
        SomeDouble = new ObservableProperty<double>();
    }
}

class Program
{
    static void Main(string[] args)
    {
        SomeClass someobject = new SomeClass();
        const double lam = 1.0;
        using (var sub = someobject.SomeDouble.Observable
            .TakeWhile((oldvalue, newvalue) => 
                Math.Abs(oldvalue - newvalue) > lam)
            .Subscribe(x => 
                Console.WriteLine("{0}\t{1}",x,someobject.SomeDouble.Value)))
        {
            someobject.SomeDouble.Value = 3.0;
            someobject.SomeDouble.Value = 2.0;
            someobject.SomeDouble.Value = 1.0;
            someobject.SomeDouble.Value = -1.0;
        }
    }
}

出力で

3       3
1       1
-1      -1

ラムダは、カスタム拡張メソッドのパラメーターですTakeWhile

観察可能なプロパティのラッパーは次のようになります (完全ではない可能性があります)。

/// Wrapper for properties that notify their change by means of an observable sequence
class ObservableProperty<T>
{
    T val;
    ISubject<T> sub = new Subject<T>();

    public T Value
    {
        get { return val; }
        set
        {
            val = value;
            sub.OnNext(value);
        }
    }

    public IObservable<T> Observable
    {
        get { return sub; }
    }
}

カスタム拡張メソッドは次のとおりです。

public static class Extensions
{
    /// Return distinct values from source while AdjacentCompare is true
    public static IObservable<TSource> TakeWhile<TSource>(this IObservable<TSource> source, Func<TSource, TSource, bool> AdjacentCompare)
    {
        return source.Scan((oldvalue, newvalue) =>
        {
            if (AdjacentCompare(oldvalue, newvalue))
                return newvalue;
            return oldvalue;
        }).DistinctUntilChanged();
    }
}

ヘルパー クラスと拡張メソッドは比較的長く見える場合がありますが、これらは一般的なものです。つまり、値を比較する方法やそれらの型 (おそらく実装によって制限される) は問題ではなく、rx の利点が得られます。サブスクリプションの有効期間を簡単に制御し、スレッド セーフを実現し、宣言型コードを記述します。

少し前に検索中に、このライブラリに出くわしました: ReactiveProperty

于 2013-01-21T20:34:31.927 に答える