Skip to content

Commit

Permalink
perf: use less rx operators (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
cabauman authored Dec 14, 2020
1 parent 599391a commit 2e4a25e
Showing 1 changed file with 69 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,39 @@ public static IObservable<TReturn> WhenPropertyValueChanges<TObj, TReturn>(
throw new ArgumentNullException(nameof(propertyExpression));
}

return WhenPropertyChanges(objectToMonitor, propertyExpression).Select(x => x.Value);
IObservable<INotifyPropertyChanged> currentObservable = Observable.Return((INotifyPropertyChanged)objectToMonitor);

var expressionChain = propertyExpression.Body.GetExpressionChain();

if (expressionChain.Count == 0)
{
throw new ArgumentException("There are no properties in the expressions", nameof(propertyExpression));
}

var i = 0;
foreach (var memberExpression in expressionChain)
{
var memberInfo = memberExpression.Member;

if (i == expressionChain.Count - 1)
{
return Observable.Return(memberInfo)
.CombineLatest(currentObservable, (memberInfo, parent) => (memberInfo, value: parent))
.Where(x => x.value != null)
.Select(x => GenerateObservable(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, TReturn>.GetCache(x.memberInfo)))
.Switch();
}

currentObservable = Observable.Return(memberInfo)
.CombineLatest(currentObservable, (memberInfo, parent) => (memberInfo, value: parent))
.Where(x => x.value != null)
.Select(x => GenerateObservable(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, INotifyPropertyChanged>.GetCache(x.memberInfo)))
.Switch();

i++;
}

throw new ArgumentException("Invalid expression", nameof(propertyExpression));
}

/// <summary>
Expand Down Expand Up @@ -77,14 +109,14 @@ public static IObservable<TReturn> WhenPropertyValueChanges<TObj, TReturn>(
return Observable.Return(memberInfo)
.CombineLatest(currentObservable, (memberInfo, parent) => (memberInfo, sender: parent.Sender, value: parent.Value))
.Where(x => x.value != null)
.Select(x => GenerateObservable(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, TReturn>.GetCache(x.memberInfo)))
.Select(x => GenerateObservableWithSender(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, TReturn>.GetCache(x.memberInfo)))
.Switch();
}

currentObservable = Observable.Return(memberInfo)
.CombineLatest(currentObservable, (memberInfo, parent) => (memberInfo, sender: parent.Sender, value: parent.Value))
.Where(x => x.value != null)
.Select(x => GenerateObservable(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, INotifyPropertyChanged>.GetCache(x.memberInfo)))
.Select(x => GenerateObservableWithSender(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, INotifyPropertyChanged>.GetCache(x.memberInfo)))
.Switch();

i++;
Expand All @@ -93,22 +125,51 @@ public static IObservable<TReturn> WhenPropertyValueChanges<TObj, TReturn>(
throw new ArgumentException("Invalid expression", nameof(propertyExpression));
}

private static IObservable<(object Sender, T Value)> GenerateObservable<T>(
private static IObservable<T> GenerateObservable<T>(
INotifyPropertyChanged parent,
MemberInfo memberInfo,
Func<INotifyPropertyChanged, T> getter)
{
var memberName = memberInfo.Name;
return Observable.FromEvent<PropertyChangedEventHandler, (object Sender, PropertyChangedEventArgs Args)>(
return Observable.FromEvent<PropertyChangedEventHandler, T>(
handler =>
{
void Handler(object sender, PropertyChangedEventArgs e) => handler((sender, e));
void Handler(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == memberName)
{
handler(getter(parent));
}
}
return Handler;
},
x => parent.PropertyChanged += x,
x => parent.PropertyChanged -= x)
.StartWith(getter(parent));
}

private static IObservable<(object Sender, T Value)> GenerateObservableWithSender<T>(
INotifyPropertyChanged parent,
MemberInfo memberInfo,
Func<INotifyPropertyChanged, T> getter)
{
var memberName = memberInfo.Name;
return Observable.FromEvent<PropertyChangedEventHandler, (object Sender, T Value)>(
handler =>
{
void Handler(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == memberName)
{
handler((sender, getter(parent)));
}
}
return Handler;
},
x => parent.PropertyChanged += x,
x => parent.PropertyChanged -= x)
.Where(x => x.Args.PropertyName == memberName)
.Select(x => (x.Sender, getter(parent)))
.StartWith((parent, getter(parent)));
}
}
Expand Down

0 comments on commit 2e4a25e

Please sign in to comment.