Skip to content

Commit

Permalink
Document public API
Browse files Browse the repository at this point in the history
  • Loading branch information
thomaslevesque committed Sep 30, 2019
1 parent 10ecde8 commit 6a05a2d
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 5 deletions.
52 changes: 49 additions & 3 deletions src/WeakEvent/AsyncWeakEventSource.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,84 @@
using System;
using System.Threading.Tasks;
using static WeakEvent.WeakEventSourceHelper;

namespace WeakEvent
{
/// <summary>
/// Represents the method that will handle an event asynchronously when the event provides data.
/// </summary>
/// <typeparam name="TEventArgs">The type of the event data generated by the event.</typeparam>
/// <param name="sender">The source of the event.</param>
/// <param name="e">An object that contains the event data.</param>
/// <returns></returns>
public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e);


/// <summary>
/// An async event with weak subscription, i.e. it won't keep handlers from being garbage collected.
/// </summary>
/// <typeparam name="TEventArgs">The type of the event data generated by the event.</typeparam>
public class AsyncWeakEventSource<TEventArgs>
{
private DelegateCollection? _handlers;

public async Task RaiseAsync(object? sender, TEventArgs e)
/// <summary>
/// Raises the event by invoking each handler that hasn't been garbage collected.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="args">An object that contains the event data.</param>
/// <remarks>The handlers are invoked one after the other, in the order they were subscribed in.
/// Each handler is awaited before invoking the next one.</remarks>
public async Task RaiseAsync(object? sender, TEventArgs args)
{
var validHandlers = GetValidHandlers(_handlers);
foreach (var handler in validHandlers)
{
await handler.Invoke(sender, e);
await handler.Invoke(sender, args);
}
}

/// <summary>
/// Adds an event handler.
/// </summary>
/// <param name="handler">The handler to subscribe.</param>
/// <remarks>Only a weak reference to the handler's <c>Target</c> is kept, so that it can be garbage collected.</remarks>
public void Subscribe(AsyncEventHandler<TEventArgs> handler)
{
Subscribe(null, handler);
}

/// <summary>
/// Adds an event handler, specifying a lifetime object.
/// </summary>
/// <param name="lifetimeObject">An object that keeps the handler alive as long as it's alive.</param>
/// <param name="handler">The handler to subscribe.</param>
/// <remarks>Only a weak reference to the handler's <c>Target</c> is kept, so that it can be garbage collected.
/// However, as long as the <c>lifetime</c> object is alive, the handler will be kept alive. This is useful for
/// subscribing with anonymous methods (e.g. lambda expressions). Note that you must specify the same lifetime
/// object to unsubscribe, otherwise the handler's lifetime will remain tied to the lifetime object.</remarks>
public void Subscribe(object? lifetimeObject, AsyncEventHandler<TEventArgs> handler)
{
Subscribe<DelegateCollection, OpenEventHandler, StrongHandler>(lifetimeObject, ref _handlers, handler);
}

/// <summary>
/// Removes an event handler.
/// </summary>
/// <param name="handler">The handler to unsubscribe.</param>
/// <remarks>The behavior is the same as that of <see cref="Delegate.Remove(Delegate, Delegate)"/>. Only the last instance
/// of the handler's invocation list is removed. If the exact invocation list is not found, nothing is removed.</remarks>
public void Unsubscribe(AsyncEventHandler<TEventArgs> handler)
{
Unsubscribe(null, handler);
}

/// <summary>
/// Removes an event handler that was subscribed with a lifetime object.
/// </summary>
/// <param name="lifetimeObject">The lifetime object that was associated with the handler.</param>
/// <param name="handler">The handler to unsubscribe.</param>
/// <remarks>The behavior is the same as that of <see cref="Delegate.Remove(Delegate, Delegate)"/>. Only the last instance
/// of the handler's invocation list is removed. If the exact invocation list is not found, nothing is removed.</remarks>
public void Unsubscribe(object? lifetimeObject, AsyncEventHandler<TEventArgs> handler)
{
Unsubscribe<OpenEventHandler, StrongHandler>(lifetimeObject, _handlers, handler);
Expand Down
1 change: 1 addition & 0 deletions src/WeakEvent/WeakEvent.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<AssemblyOriginatorKeyFile>WeakEvent.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<MinVerVerbosity>quiet</MinVerVerbosity>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<PropertyGroup Label="Package properties">
Expand Down
41 changes: 39 additions & 2 deletions src/WeakEvent/WeakEventSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,74 @@

namespace WeakEvent
{
/// <summary>
/// An event with weak subscription, i.e. it won't keep handlers from being garbage collected.
/// </summary>
/// <typeparam name="TEventArgs">The type of the event's arguments.</typeparam>
public class WeakEventSource<TEventArgs>
#if NET40
where TEventArgs : EventArgs
#endif
{
private DelegateCollection? _handlers;

public void Raise(object? sender, TEventArgs e)
/// <summary>
/// Raises the event by invoking each handler that hasn't been garbage collected.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="args">An object that contains the event data.</param>
/// <remarks>The handlers are invoked one after the other, in the order they were subscribed in.</remarks>
public void Raise(object? sender, TEventArgs args)
{
var validHandlers = GetValidHandlers(_handlers);
foreach (var handler in validHandlers)
{
handler.Invoke(sender, e);
handler.Invoke(sender, args);
}
}

/// <summary>
/// Adds an event handler.
/// </summary>
/// <param name="handler">The handler to subscribe.</param>
/// <remarks>Only a weak reference to the handler's <c>Target</c> is kept, so that it can be garbage collected.</remarks>
public void Subscribe(EventHandler<TEventArgs> handler)
{
Subscribe(null, handler);
}

/// <summary>
/// Adds an event handler, specifying a lifetime object.
/// </summary>
/// <param name="lifetimeObject">An object that keeps the handler alive as long as it's alive.</param>
/// <param name="handler">The handler to subscribe.</param>
/// <remarks>Only a weak reference to the handler's <c>Target</c> is kept, so that it can be garbage collected.
/// However, as long as the <c>lifetime</c> object is alive, the handler will be kept alive. This is useful for
/// subscribing with anonymous methods (e.g. lambda expressions). Note that you must specify the same lifetime
/// object to unsubscribe, otherwise the handler's lifetime will remain tied to the lifetime object.</remarks>
public void Subscribe(object? lifetimeObject, EventHandler<TEventArgs> handler)
{
Subscribe<DelegateCollection, OpenEventHandler, StrongHandler>(lifetimeObject, ref _handlers, handler);
}

/// <summary>
/// Removes an event handler.
/// </summary>
/// <param name="handler">The handler to unsubscribe.</param>
/// <remarks>The behavior is the same as that of <see cref="Delegate.Remove(Delegate, Delegate)"/>. Only the last instance
/// of the handler's invocation list is removed. If the exact invocation list is not found, nothing is removed.</remarks>
public void Unsubscribe(EventHandler<TEventArgs> handler)
{
Unsubscribe(null, handler);
}

/// <summary>
/// Removes an event handler that was subscribed with a lifetime object.
/// </summary>
/// <param name="lifetimeObject">The lifetime object that was associated with the handler.</param>
/// <param name="handler">The handler to unsubscribe.</param>
/// <remarks>The behavior is the same as that of <see cref="Delegate.Remove(Delegate, Delegate)"/>. Only the last instance
/// of the handler's invocation list is removed. If the exact invocation list is not found, nothing is removed.</remarks>
public void Unsubscribe(object? lifetimeObject, EventHandler<TEventArgs> handler)
{
Unsubscribe<OpenEventHandler, StrongHandler>(lifetimeObject, _handlers, handler);
Expand Down

0 comments on commit 6a05a2d

Please sign in to comment.