Skip to content

Commit 2e4a25e

Browse files
authored
perf: use less rx operators (#104)
1 parent 599391a commit 2e4a25e

File tree

1 file changed

+69
-8
lines changed

1 file changed

+69
-8
lines changed

src/ReactiveMarbles.PropertyChanged/NotifyPropertyChangedExtensions.cs

+69-8
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,39 @@ public static IObservable<TReturn> WhenPropertyValueChanges<TObj, TReturn>(
3535
throw new ArgumentNullException(nameof(propertyExpression));
3636
}
3737

38-
return WhenPropertyChanges(objectToMonitor, propertyExpression).Select(x => x.Value);
38+
IObservable<INotifyPropertyChanged> currentObservable = Observable.Return((INotifyPropertyChanged)objectToMonitor);
39+
40+
var expressionChain = propertyExpression.Body.GetExpressionChain();
41+
42+
if (expressionChain.Count == 0)
43+
{
44+
throw new ArgumentException("There are no properties in the expressions", nameof(propertyExpression));
45+
}
46+
47+
var i = 0;
48+
foreach (var memberExpression in expressionChain)
49+
{
50+
var memberInfo = memberExpression.Member;
51+
52+
if (i == expressionChain.Count - 1)
53+
{
54+
return Observable.Return(memberInfo)
55+
.CombineLatest(currentObservable, (memberInfo, parent) => (memberInfo, value: parent))
56+
.Where(x => x.value != null)
57+
.Select(x => GenerateObservable(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, TReturn>.GetCache(x.memberInfo)))
58+
.Switch();
59+
}
60+
61+
currentObservable = Observable.Return(memberInfo)
62+
.CombineLatest(currentObservable, (memberInfo, parent) => (memberInfo, value: parent))
63+
.Where(x => x.value != null)
64+
.Select(x => GenerateObservable(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, INotifyPropertyChanged>.GetCache(x.memberInfo)))
65+
.Switch();
66+
67+
i++;
68+
}
69+
70+
throw new ArgumentException("Invalid expression", nameof(propertyExpression));
3971
}
4072

4173
/// <summary>
@@ -77,14 +109,14 @@ public static IObservable<TReturn> WhenPropertyValueChanges<TObj, TReturn>(
77109
return Observable.Return(memberInfo)
78110
.CombineLatest(currentObservable, (memberInfo, parent) => (memberInfo, sender: parent.Sender, value: parent.Value))
79111
.Where(x => x.value != null)
80-
.Select(x => GenerateObservable(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, TReturn>.GetCache(x.memberInfo)))
112+
.Select(x => GenerateObservableWithSender(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, TReturn>.GetCache(x.memberInfo)))
81113
.Switch();
82114
}
83115

84116
currentObservable = Observable.Return(memberInfo)
85117
.CombineLatest(currentObservable, (memberInfo, parent) => (memberInfo, sender: parent.Sender, value: parent.Value))
86118
.Where(x => x.value != null)
87-
.Select(x => GenerateObservable(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, INotifyPropertyChanged>.GetCache(x.memberInfo)))
119+
.Select(x => GenerateObservableWithSender(x.value, x.memberInfo, GetMemberFuncCache<INotifyPropertyChanged, INotifyPropertyChanged>.GetCache(x.memberInfo)))
88120
.Switch();
89121

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

96-
private static IObservable<(object Sender, T Value)> GenerateObservable<T>(
128+
private static IObservable<T> GenerateObservable<T>(
97129
INotifyPropertyChanged parent,
98130
MemberInfo memberInfo,
99131
Func<INotifyPropertyChanged, T> getter)
100132
{
101133
var memberName = memberInfo.Name;
102-
return Observable.FromEvent<PropertyChangedEventHandler, (object Sender, PropertyChangedEventArgs Args)>(
134+
return Observable.FromEvent<PropertyChangedEventHandler, T>(
103135
handler =>
104136
{
105-
void Handler(object sender, PropertyChangedEventArgs e) => handler((sender, e));
137+
void Handler(object sender, PropertyChangedEventArgs e)
138+
{
139+
if (e.PropertyName == memberName)
140+
{
141+
handler(getter(parent));
142+
}
143+
}
144+
145+
return Handler;
146+
},
147+
x => parent.PropertyChanged += x,
148+
x => parent.PropertyChanged -= x)
149+
.StartWith(getter(parent));
150+
}
151+
152+
private static IObservable<(object Sender, T Value)> GenerateObservableWithSender<T>(
153+
INotifyPropertyChanged parent,
154+
MemberInfo memberInfo,
155+
Func<INotifyPropertyChanged, T> getter)
156+
{
157+
var memberName = memberInfo.Name;
158+
return Observable.FromEvent<PropertyChangedEventHandler, (object Sender, T Value)>(
159+
handler =>
160+
{
161+
void Handler(object sender, PropertyChangedEventArgs e)
162+
{
163+
if (e.PropertyName == memberName)
164+
{
165+
handler((sender, getter(parent)));
166+
}
167+
}
168+
106169
return Handler;
107170
},
108171
x => parent.PropertyChanged += x,
109172
x => parent.PropertyChanged -= x)
110-
.Where(x => x.Args.PropertyName == memberName)
111-
.Select(x => (x.Sender, getter(parent)))
112173
.StartWith((parent, getter(parent)));
113174
}
114175
}

0 commit comments

Comments
 (0)