Skip to content

Commit 2ac9109

Browse files
authored
fix: Memory usage of OAPH and ReactiveObject (#1936)
1 parent fa639da commit 2ac9109

File tree

7 files changed

+132
-130
lines changed

7 files changed

+132
-130
lines changed

src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.net461.approved.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,11 @@ namespace ReactiveUI
277277
}
278278
public class static IReactiveObjectExtensions
279279
{
280-
public static TRet RaiseAndSetIfChanged<TObj, TRet>(this TObj @this, ref TRet backingField, TRet newValue, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
280+
public static TRet RaiseAndSetIfChanged<TObj, TRet>(this TObj reactiveObject, ref TRet backingField, TRet newValue, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
281281
where TObj : ReactiveUI.IReactiveObject { }
282-
public static void RaisePropertyChanged<TSender>(this TSender @this, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
282+
public static void RaisePropertyChanged<TSender>(this TSender reactiveObject, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
283283
where TSender : ReactiveUI.IReactiveObject { }
284-
public static void RaisePropertyChanging<TSender>(this TSender @this, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
284+
public static void RaisePropertyChanging<TSender>(this TSender reactiveObject, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
285285
where TSender : ReactiveUI.IReactiveObject { }
286286
}
287287
public interface IReactivePropertyChangedEventArgs<out TSender>

src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.netcoreapp2.0.approved.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -271,11 +271,11 @@ namespace ReactiveUI
271271
}
272272
public class static IReactiveObjectExtensions
273273
{
274-
public static TRet RaiseAndSetIfChanged<TObj, TRet>(this TObj @this, ref TRet backingField, TRet newValue, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
274+
public static TRet RaiseAndSetIfChanged<TObj, TRet>(this TObj reactiveObject, ref TRet backingField, TRet newValue, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
275275
where TObj : ReactiveUI.IReactiveObject { }
276-
public static void RaisePropertyChanged<TSender>(this TSender @this, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
276+
public static void RaisePropertyChanged<TSender>(this TSender reactiveObject, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
277277
where TSender : ReactiveUI.IReactiveObject { }
278-
public static void RaisePropertyChanging<TSender>(this TSender @this, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
278+
public static void RaisePropertyChanging<TSender>(this TSender reactiveObject, [System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
279279
where TSender : ReactiveUI.IReactiveObject { }
280280
}
281281
public interface IReactivePropertyChangedEventArgs<out TSender>

src/ReactiveUI.Tests/ObservableAsPropertyHelper/ObservableAsPropertyHelperTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public void NoThrownExceptionsSubscriberEqualsOAPHDeath()
194194
new TestScheduler().With(sched =>
195195
{
196196
var input = new Subject<int>();
197-
var fixture = new ObservableAsPropertyHelper<int>(input, _ => { }, -5);
197+
var fixture = new ObservableAsPropertyHelper<int>(input, _ => { }, -5, scheduler: ImmediateScheduler.Instance);
198198

199199
Assert.Equal(-5, fixture.Value);
200200
new[] { 1, 2, 3, 4 }.Run(x => input.OnNext(x));

src/ReactiveUI/ObservableForProperty/OAPHCreationHelperMixin.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static class OAPHCreationHelperMixin
2020
/// automatically provides the onChanged method to raise the property
2121
/// changed notification.
2222
/// </summary>
23-
/// <typeparam name="TObj">The onject type.</typeparam>
23+
/// <typeparam name="TObj">The object type.</typeparam>
2424
/// <typeparam name="TRet">The result type.</typeparam>
2525
/// <param name="target">
2626
/// The observable to convert to an ObservableAsPropertyHelper.
@@ -114,7 +114,7 @@ public static ObservableAsPropertyHelper<TRet> ToProperty<TObj, TRet>(
114114
/// automatically provides the onChanged method to raise the property
115115
/// changed notification.
116116
/// </summary>
117-
/// <typeparam name="TObj">The onject type.</typeparam>
117+
/// <typeparam name="TObj">The object type.</typeparam>
118118
/// <typeparam name="TRet">The result type.</typeparam>
119119
/// <param name="target">
120120
/// The observable to convert to an ObservableAsPropertyHelper.
@@ -157,7 +157,7 @@ public static ObservableAsPropertyHelper<TRet> ToProperty<TObj, TRet>(
157157
/// automatically provides the onChanged method to raise the property
158158
/// changed notification.
159159
/// </summary>
160-
/// <typeparam name="TObj">The onject type.</typeparam>
160+
/// <typeparam name="TObj">The object type.</typeparam>
161161
/// <typeparam name="TRet">The result type.</typeparam>
162162
/// <param name="target">
163163
/// The observable to convert to an ObservableAsPropertyHelper.
@@ -234,15 +234,13 @@ private static ObservableAsPropertyHelper<TRet> ObservableToProperty<TObj, TRet>
234234
name += "[]";
235235
}
236236

237-
var ret = new ObservableAsPropertyHelper<TRet>(
237+
return new ObservableAsPropertyHelper<TRet>(
238238
observable,
239239
_ => target.RaisingPropertyChanged(name),
240240
_ => target.RaisingPropertyChanging(name),
241241
initialValue,
242242
deferSubscription,
243243
scheduler);
244-
245-
return ret;
246244
}
247245

248246
private static ObservableAsPropertyHelper<TRet> ObservableToProperty<TObj, TRet>(

src/ReactiveUI/ObservableForProperty/ObservableAsPropertyHelper.cs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ namespace ReactiveUI
2424
/// <typeparam name="T">The type.</typeparam>
2525
public sealed class ObservableAsPropertyHelper<T> : IHandleObservableErrors, IDisposable, IEnableLogger
2626
{
27-
private readonly IConnectableObservable<T> _source;
27+
private readonly Lazy<ISubject<Exception>> _thrownExceptions;
28+
private readonly IObservable<T> _source;
29+
private readonly ISubject<T> _subject;
2830
private T _lastValue;
29-
private IDisposable _inner;
31+
private CompositeDisposable _disposable = new CompositeDisposable();
3032
private int _activated;
3133

3234
/// <summary>
@@ -103,25 +105,24 @@ public ObservableAsPropertyHelper(
103105
scheduler = scheduler ?? CurrentThreadScheduler.Instance;
104106
onChanging = onChanging ?? (_ => { });
105107

106-
var subj = new ScheduledSubject<T>(scheduler);
107-
var exSubject = new ScheduledSubject<Exception>(CurrentThreadScheduler.Instance, RxApp.DefaultExceptionHandler);
108-
109-
subj.Subscribe(
108+
_subject = new ScheduledSubject<T>(scheduler);
109+
_subject.Subscribe(
110110
x =>
111111
{
112112
onChanging(x);
113113
_lastValue = x;
114114
onChanged(x);
115115
},
116-
exSubject.OnNext);
116+
ex => _thrownExceptions.Value.OnNext(ex))
117+
.DisposeWith(_disposable);
117118

118-
ThrownExceptions = exSubject;
119+
_thrownExceptions = new Lazy<ISubject<Exception>>(() => new ScheduledSubject<Exception>(CurrentThreadScheduler.Instance, RxApp.DefaultExceptionHandler));
119120

120121
_lastValue = initialValue;
121-
_source = observable.StartWith(initialValue).DistinctUntilChanged().Multicast(subj);
122+
_source = observable.StartWith(initialValue).DistinctUntilChanged();
122123
if (!deferSubscription)
123124
{
124-
_inner = _source.Connect();
125+
_source.Subscribe(_subject).DisposeWith(_disposable);
125126
_activated = 1;
126127
}
127128
}
@@ -135,7 +136,7 @@ public T Value
135136
{
136137
if (Interlocked.CompareExchange(ref _activated, 1, 0) == 0)
137138
{
138-
_inner = _source.Connect();
139+
_source.Subscribe(_subject).DisposeWith(_disposable);
139140
}
140141

141142
return _lastValue;
@@ -154,7 +155,7 @@ public T Value
154155
/// Gets an observable which signals whenever an exception would normally terminate ReactiveUI
155156
/// internal state.
156157
/// </summary>
157-
public IObservable<Exception> ThrownExceptions { get; }
158+
public IObservable<Exception> ThrownExceptions => _thrownExceptions.Value;
158159

159160
/// <summary>
160161
/// Constructs a "default" ObservableAsPropertyHelper object. This is
@@ -177,10 +178,8 @@ public T Value
177178
/// </summary>
178179
public void Dispose()
179180
{
180-
(_inner ?? Disposable.Empty).Dispose();
181-
_inner = null;
181+
_disposable?.Dispose();
182+
_disposable = null;
182183
}
183184
}
184185
}
185-
186-
// vim: tw=120 ts=4 sw=4 et :

0 commit comments

Comments
 (0)