假设我在课堂上有一些事件:
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不是事件的想法。
这个问题最优雅的解决方案是什么?
答案 0 :(得分:5)
(我建议不使用术语“lambda”,因为你也使用了lambda表达式。听起来你对变化感兴趣,即delta。)< / p>
您可以创建自己的静态方法来创建适当的委托:
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表达式上使用扩展方法,这会使这更容易。
答案 1 :(得分:1)
你可以写这样的东西
SomeObject.SomeDoubleChange += (d) => DoWork(lambda, d, (d) => {});
private void DoWork(double minLambda, double currentValue, ChangedEventHandler handler)
{
if(abs(currentValue - oldValue) > minLambda))
{
handler(currentValue);
}
}
答案 2 :(得分:0)
我最喜欢的“优雅”方式是使用observable而不是事件,特别是在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