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