[英]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.