赋予委托属性的优雅方式
本文关键字:方式 属性 | 更新日期: 2023-09-27 17:54:43
假设我在一个类中有一些事件:
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) => {};
我唯一想到的实现这一点的方法是放弃整个event关键字并实现一个带有+=和-=操作符的容器,对指定的委托进行操作。但在我看来,这不是一个非常优雅的解决方案,因为它给了someeclass的用户一个想法,即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);
}
}
我最喜欢的"优雅"方式是使用可观察对象而不是事件,特别是在响应式扩展的帮助下实现的。想象一下,如果能够这样做:
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();
}
}
helper类和扩展方法看起来比较长,但它们是泛型的,也就是说,您如何比较值以及它们的类型(可能受实现的限制)并不重要,并且您可以轻松地控制订阅生命周期、线程安全性和编写声明性代码。
当搜索前一段时间,我遇到了这个库:ReactiveProperty