簡體   English   中英

賦予代表屬性的優雅方式

[英]Elegant way to give a delegate properties

假設我在課堂上有一些事件:

 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不是事件。

解決這個問題的最優雅的方法是什么?

(鑒於您也在使用lambda表達式,因此我建議您不要在這里使用術語“ lambda”。聽起來您對更改(即增量)感興趣。)

您可以創建自己的靜態方法來創建適當的委托:

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 => ...);

不幸的是,您不能在lambda表達式上使用擴展方法,這會使此操作變得更容易。

你可以這樣寫東西

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

private void DoWork(double minLambda, double currentValue, ChangedEventHandler handler)
{
  if(abs(currentValue - oldValue) > minLambda))
  {
     handler(currentValue);
  }
}

我最喜歡的“優雅”方式是通過使用可觀察對象而不是事件,尤其是在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

lambda是自定義擴展方法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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM