Skip to content

Commit

Permalink
Merge pull request #376 from Reactive-Extensions/MiscBaseClassImprove…
Browse files Browse the repository at this point in the history
…ments

Some improvements to core classes
  • Loading branch information
bartdesmet committed Apr 14, 2017
2 parents a4d0a54 + 93a63f6 commit 7bfd6c3
Show file tree
Hide file tree
Showing 18 changed files with 164 additions and 150 deletions.
6 changes: 3 additions & 3 deletions Rx.NET/Source/src/System.Reactive/AnonymousObservable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace System.Reactive
{
/// <summary>
/// Class to create an <see cref="IObservable{T}"/> instance from a delegate-based implementation of the Subscribe method.
/// Class to create an <see cref="IObservable{T}"/> instance from a delegate-based implementation of the <see cref="IObservable{T}.Subscribe(IObserver{T})"/> method.
/// </summary>
/// <typeparam name="T">The type of the elements in the sequence.</typeparam>
public sealed class AnonymousObservable<T> : ObservableBase<T>
Expand All @@ -17,8 +17,8 @@ public sealed class AnonymousObservable<T> : ObservableBase<T>
/// <summary>
/// Creates an observable sequence object from the specified subscription function.
/// </summary>
/// <param name="subscribe">Subscribe method implementation.</param>
/// <exception cref="ArgumentNullException"><paramref name="subscribe"/> is null.</exception>
/// <param name="subscribe"><see cref="IObservable{T}.Subscribe(IObserver{T})"/> method implementation.</param>
/// <exception cref="ArgumentNullException"><paramref name="subscribe"/> is <c>null</c>.</exception>
public AnonymousObservable(Func<IObserver<T>, IDisposable> subscribe)
{
if (subscribe == null)
Expand Down
58 changes: 23 additions & 35 deletions Rx.NET/Source/src/System.Reactive/AnonymousObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ public sealed class AnonymousObserver<T> : ObserverBase<T>
private readonly Action _onCompleted;

/// <summary>
/// Creates an observer from the specified OnNext, OnError, and OnCompleted actions.
/// Creates an observer from the specified <see cref="IObserver{T}.OnNext(T)"/>, <see cref="IObserver{T}.OnError(Exception)"/>, and <see cref="IObserver{T}.OnCompleted()"/> actions.
/// </summary>
/// <param name="onNext">Observer's OnNext action implementation.</param>
/// <param name="onError">Observer's OnError action implementation.</param>
/// <param name="onCompleted">Observer's OnCompleted action implementation.</param>
/// <exception cref="ArgumentNullException"><paramref name="onNext"/> or <paramref name="onError"/> or <paramref name="onCompleted"/> is null.</exception>
/// <param name="onNext">Observer's <see cref="IObserver{T}.OnNext(T)"/> action implementation.</param>
/// <param name="onError">Observer's <see cref="IObserver{T}.OnError(Exception)"/> action implementation.</param>
/// <param name="onCompleted">Observer's <see cref="IObserver{T}.OnCompleted()"/> action implementation.</param>
/// <exception cref="ArgumentNullException"><paramref name="onNext"/> or <paramref name="onError"/> or <paramref name="onCompleted"/> is <c>null</c>.</exception>
public AnonymousObserver(Action<T> onNext, Action<Exception> onError, Action onCompleted)
{
if (onNext == null)
Expand All @@ -36,66 +36,54 @@ public AnonymousObserver(Action<T> onNext, Action<Exception> onError, Action onC
}

/// <summary>
/// Creates an observer from the specified OnNext action.
/// Creates an observer from the specified <see cref="IObserver{T}.OnNext(T)"/> action.
/// </summary>
/// <param name="onNext">Observer's OnNext action implementation.</param>
/// <exception cref="ArgumentNullException"><paramref name="onNext"/> is null.</exception>
/// <param name="onNext">Observer's <see cref="IObserver{T}.OnNext(T)"/> action implementation.</param>
/// <exception cref="ArgumentNullException"><paramref name="onNext"/> is <c>null</c>.</exception>
public AnonymousObserver(Action<T> onNext)
: this(onNext, Stubs.Throw, Stubs.Nop)
{
}

/// <summary>
/// Creates an observer from the specified OnNext and OnError actions.
/// Creates an observer from the specified <see cref="IObserver{T}.OnNext(T)"/> and <see cref="IObserver{T}.OnError(Exception)"/> actions.
/// </summary>
/// <param name="onNext">Observer's OnNext action implementation.</param>
/// <param name="onError">Observer's OnError action implementation.</param>
/// <exception cref="ArgumentNullException"><paramref name="onNext"/> or <paramref name="onError"/> is null.</exception>
/// <param name="onNext">Observer's <see cref="IObserver{T}.OnNext(T)"/> action implementation.</param>
/// <param name="onError">Observer's <see cref="IObserver{T}.OnError(Exception)"/> action implementation.</param>
/// <exception cref="ArgumentNullException"><paramref name="onNext"/> or <paramref name="onError"/> is <c>null</c>.</exception>
public AnonymousObserver(Action<T> onNext, Action<Exception> onError)
: this(onNext, onError, Stubs.Nop)
{
}

/// <summary>
/// Creates an observer from the specified OnNext and OnCompleted actions.
/// Creates an observer from the specified <see cref="IObserver{T}.OnNext(T)"/> and <see cref="IObserver{T}.OnCompleted()"/> actions.
/// </summary>
/// <param name="onNext">Observer's OnNext action implementation.</param>
/// <param name="onCompleted">Observer's OnCompleted action implementation.</param>
/// <exception cref="ArgumentNullException"><paramref name="onNext"/> or <paramref name="onCompleted"/> is null.</exception>
/// <param name="onNext">Observer's <see cref="IObserver{T}.OnNext(T)"/> action implementation.</param>
/// <param name="onCompleted">Observer's <see cref="IObserver{T}.OnCompleted()"/> action implementation.</param>
/// <exception cref="ArgumentNullException"><paramref name="onNext"/> or <paramref name="onCompleted"/> is <c>null</c>.</exception>
public AnonymousObserver(Action<T> onNext, Action onCompleted)
: this(onNext, Stubs.Throw, onCompleted)
{
}

/// <summary>
/// Calls the onNext action.
/// Calls the action implementing <see cref="IObserver{T}.OnNext(T)"/>.
/// </summary>
/// <param name="value">Next element in the sequence.</param>
protected override void OnNextCore(T value)
{
_onNext(value);
}
protected override void OnNextCore(T value) => _onNext(value);

/// <summary>
/// Calls the onError action.
/// Calls the action implementing <see cref="IObserver{T}.OnError(Exception)"/>.
/// </summary>
/// <param name="error">The error that has occurred.</param>
protected override void OnErrorCore(Exception error)
{
_onError(error);
}
protected override void OnErrorCore(Exception error) => _onError(error);

/// <summary>
/// Calls the onCompleted action.
/// Calls the action implementing <see cref="IObserver{T}.OnCompleted()"/>.
/// </summary>
protected override void OnCompletedCore()
{
_onCompleted();
}
protected override void OnCompletedCore() => _onCompleted();

internal IObserver<T> MakeSafe(IDisposable disposable)
{
return new AnonymousSafeObserver<T>(_onNext, _onError, _onCompleted, disposable);
}
internal IObserver<T> MakeSafe(IDisposable disposable) => new AnonymousSafeObserver<T>(_onNext, _onError, _onCompleted, disposable);
}
}
2 changes: 1 addition & 1 deletion Rx.NET/Source/src/System.Reactive/AnonymousSafeObserver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace System.Reactive
/// that accept delegates for the On* handlers. By doing the fusion, we make the call stack depth shorter which
/// helps debugging and some performance.
/// </summary>
class AnonymousSafeObserver<T> : IObserver<T>
internal sealed class AnonymousSafeObserver<T> : IObserver<T>
{
private readonly Action<T> _onNext;
private readonly Action<Exception> _onError;
Expand Down
4 changes: 2 additions & 2 deletions Rx.NET/Source/src/System.Reactive/EnlightenmentProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ namespace System.Reactive.PlatformServices
/// <summary>
/// Provides access to the platform enlightenments used by other Rx libraries to improve system performance and
/// runtime efficiency. While Rx can run without platform enlightenments loaded, it's recommended to deploy the
/// System.Reactive.PlatformServices assembly with your application and call <see cref="EnlightenmentProvider.
/// EnsureLoaded"/> during application startup to ensure enlightenments are properly loaded.
/// System.Reactive.PlatformServices assembly with your application and call <see cref="EnsureLoaded"/> during
/// application startup to ensure enlightenments are properly loaded.
/// </summary>
public static class EnlightenmentProvider
{
Expand Down
19 changes: 5 additions & 14 deletions Rx.NET/Source/src/System.Reactive/EventPattern.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ public EventPattern(TSender sender, TEventArgs e)
/// <returns><c>true</c> if both <see cref="EventPattern{TSender, TEventArgs}"/> objects represent the same event; otherwise, <c>false</c>.</returns>
public bool Equals(EventPattern<TSender, TEventArgs> other)
{
if (object.ReferenceEquals(null, other))
if (ReferenceEquals(null, other))
return false;
if (object.ReferenceEquals(this, other))
if (ReferenceEquals(this, other))
return true;

return EqualityComparer<TSender>.Default.Equals(Sender, other.Sender) && EqualityComparer<TEventArgs>.Default.Equals(EventArgs, other.EventArgs);
Expand All @@ -71,10 +71,7 @@ public bool Equals(EventPattern<TSender, TEventArgs> other)
/// </summary>
/// <param name="obj">The System.Object to compare with the current <see cref="EventPattern{TSender, TEventArgs}"/>.</param>
/// <returns><c>true</c> if the specified System.Object is equal to the current <see cref="EventPattern{TSender, TEventArgs}"/>; otherwise, <c>false</c>.</returns>
public override bool Equals(object obj)
{
return Equals(obj as EventPattern<TSender, TEventArgs>);
}
public override bool Equals(object obj) => Equals(obj as EventPattern<TSender, TEventArgs>);

/// <summary>
/// Returns the hash code for the current <see cref="EventPattern{TSender, TEventArgs}"/> instance.
Expand All @@ -93,20 +90,14 @@ public override int GetHashCode()
/// <param name="first">The first <see cref="EventPattern{TSender, TEventArgs}"/> to compare, or <c>null</c>.</param>
/// <param name="second">The second <see cref="EventPattern{TSender, TEventArgs}"/> to compare, or <c>null</c>.</param>
/// <returns><c>true</c> if both <see cref="EventPattern{TSender, TEventArgs}"/> objects represent the same event; otherwise, <c>false</c>.</returns>
public static bool operator ==(EventPattern<TSender, TEventArgs> first, EventPattern<TSender, TEventArgs> second)
{
return object.Equals(first, second);
}
public static bool operator ==(EventPattern<TSender, TEventArgs> first, EventPattern<TSender, TEventArgs> second) => Equals(first, second);

/// <summary>
/// Determines whether two specified <see cref="EventPattern{TSender, TEventArgs}"/> objects represent a different event.
/// </summary>
/// <param name="first">The first <see cref="EventPattern{TSender, TEventArgs}"/> to compare, or <c>null</c>.</param>
/// <param name="second">The second <see cref="EventPattern{TSender, TEventArgs}"/> to compare, or <c>null</c>.</param>
/// <returns><c>true</c> if both <see cref="EventPattern{TSender, TEventArgs}"/> objects don't represent the same event; otherwise, <c>false</c>.</returns>
public static bool operator !=(EventPattern<TSender, TEventArgs> first, EventPattern<TSender, TEventArgs> second)
{
return !object.Equals(first, second);
}
public static bool operator !=(EventPattern<TSender, TEventArgs> first, EventPattern<TSender, TEventArgs> second) => !Equals(first, second);
}
}
2 changes: 1 addition & 1 deletion Rx.NET/Source/src/System.Reactive/EventPatternSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace System.Reactive
{
class EventPatternSource<TEventArgs> : EventPatternSourceBase<object, TEventArgs>, IEventPatternSource<TEventArgs>
internal sealed class EventPatternSource<TEventArgs> : EventPatternSourceBase<object, TEventArgs>, IEventPatternSource<TEventArgs>
{
public EventPatternSource(IObservable<EventPattern<object, TEventArgs>> source, Action<Action<object, TEventArgs>, /*object,*/ EventPattern<object, TEventArgs>> invokeHandler)
: base(source, invokeHandler)
Expand Down
24 changes: 16 additions & 8 deletions Rx.NET/Source/src/System.Reactive/EventPatternSourceBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public abstract class EventPatternSourceBase<TSender, TEventArgs>
/// </summary>
/// <param name="source">Source sequence to expose as an event.</param>
/// <param name="invokeHandler">Delegate used to invoke the event for each element of the sequence.</param>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="invokeHandler"/> is null.</exception>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="invokeHandler"/> is <c>null</c>.</exception>
protected EventPatternSourceBase(IObservable<EventPattern<TSender, TEventArgs>> source, Action<Action<TSender, TEventArgs>, /*object,*/ EventPattern<TSender, TEventArgs>> invokeHandler)
{
if (source == null)
Expand All @@ -40,9 +40,9 @@ protected EventPatternSourceBase(IObservable<EventPattern<TSender, TEventArgs>>
/// <summary>
/// Adds the specified event handler, causing a subscription to the underlying source.
/// </summary>
/// <param name="handler">Event handler to add. The same delegate should be passed to the Remove operation in order to remove the event handler.</param>
/// <param name="handler">Event handler to add. The same delegate should be passed to the <see cref="Remove(Delegate)"/> operation in order to remove the event handler.</param>
/// <param name="invoke">Invocation delegate to raise the event in the derived class.</param>
/// <exception cref="ArgumentNullException"><paramref name="handler"/> or <paramref name="invoke"/> is null.</exception>
/// <exception cref="ArgumentNullException"><paramref name="handler"/> or <paramref name="invoke"/> is <c>null</c>.</exception>
protected void Add(Delegate handler, Action<TSender, TEventArgs> invoke)
{
if (handler == null)
Expand All @@ -59,9 +59,13 @@ protected void Add(Delegate handler, Action<TSender, TEventArgs> invoke)
lock (gate)
{
if (isAdded)
{
Remove(handler);
}
else
{
isDone = true;
}
}
});

Expand Down Expand Up @@ -90,17 +94,19 @@ private void Add(Delegate handler, IDisposable disposable)
{
var l = new Stack<IDisposable>();
if (!_subscriptions.TryGetValue(handler, out l))
{
_subscriptions[handler] = l = new Stack<IDisposable>();
}

l.Push(disposable);
}
}

/// <summary>
/// Removes the specified event handler, causing a disposal of the corresponding subscription to the underlying source that was created during the Add operation.
/// Removes the specified event handler, causing a disposal of the corresponding subscription to the underlying source that was created during the <see cref="Add(Delegate, Action{TSender, TEventArgs})"/> operation.
/// </summary>
/// <param name="handler">Event handler to remove. This should be the same delegate as one that was passed to the Add operation.</param>
/// <exception cref="ArgumentNullException"><paramref name="handler"/> is null.</exception>
/// <param name="handler">Event handler to remove. This should be the same delegate as one that was passed to the <see cref="Add(Delegate, Action{TSender, TEventArgs})"/> operation.</param>
/// <exception cref="ArgumentNullException"><paramref name="handler"/> is <c>null</c>.</exception>
protected void Remove(Delegate handler)
{
if (handler == null)
Expand All @@ -114,13 +120,15 @@ protected void Remove(Delegate handler)
if (_subscriptions.TryGetValue(handler, out l))
{
d = l.Pop();

if (l.Count == 0)
{
_subscriptions.Remove(handler);
}
}
}

if (d != null)
d.Dispose();
d?.Dispose();
}
}
}
14 changes: 11 additions & 3 deletions Rx.NET/Source/src/System.Reactive/EventSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace System.Reactive
{
class EventSource<T> : IEventSource<T>
internal sealed class EventSource<T> : IEventSource<T>
{
private readonly IObservable<T> _source;
private readonly Dictionary<Delegate, Stack<IDisposable>> _subscriptions;
Expand All @@ -32,9 +32,13 @@ public EventSource(IObservable<T> source, Action<Action<T>, /*object,*/ T> invok
lock (gate)
{
if (isAdded)
{
Remove(value);
}
else
{
isDone = true;
}
}
});

Expand Down Expand Up @@ -69,7 +73,9 @@ private void Add(Delegate handler, IDisposable disposable)
{
var l = new Stack<IDisposable>();
if (!_subscriptions.TryGetValue(handler, out l))
{
_subscriptions[handler] = l = new Stack<IDisposable>();
}

l.Push(disposable);
}
Expand All @@ -85,13 +91,15 @@ private void Remove(Delegate handler)
if (_subscriptions.TryGetValue(handler, out l))
{
d = l.Pop();

if (l.Count == 0)
{
_subscriptions.Remove(handler);
}
}
}

if (d != null)
d.Dispose();
d?.Dispose();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ internal sealed class ExcludeFromCodeCoverageAttribute : Attribute
}
}

#endif
#endif
Loading

0 comments on commit 7bfd6c3

Please sign in to comment.