// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace CommunityToolkit.Mvvm.Messaging;
///
/// An interface for a type providing the ability to exchange messages between different objects.
/// This can be useful to decouple different modules of an application without having to keep strong
/// references to types being referenced. It is also possible to send messages to specific channels, uniquely
/// identified by a token, and to have different messengers in different sections of an applications.
/// In order to use the functionalities, first define a message type, like so:
///
/// public sealed class LoginCompletedMessage { }
///
/// Then, register a recipient for this message:
///
/// Messenger.Default.Register<MyRecipientType, LoginCompletedMessage>(this, (r, m) =>
/// {
/// // Handle the message here...
/// });
///
/// The message handler here is a lambda expression taking two parameters: the recipient and the message.
/// This is done to avoid the allocations for the closures that would've been generated if the expression
/// had captured the current instance. The recipient type parameter is used so that the recipient can be
/// directly accessed within the handler without the need to manually perform type casts. This allows the
/// code to be less verbose and more reliable, as all the checks are done just at build time. If the handler
/// is defined within the same type as the recipient, it is also possible to directly access private members.
/// This allows the message handler to be a static method, which enables the C# compiler to perform a number
/// of additional memory optimizations (such as caching the delegate, avoiding unnecessary memory allocations).
/// Finally, send a message when needed, like so:
///
/// Messenger.Default.Send<LoginCompletedMessage>();
///
/// Additionally, the method group syntax can also be used to specify the message handler
/// to invoke when receiving a message, if a method with the right signature is available
/// in the current scope. This is helpful to keep the registration and handling logic separate.
/// Following up from the previous example, consider a class having this method:
///
/// private static void Receive(MyRecipientType recipient, LoginCompletedMessage message)
/// {
/// // Handle the message there
/// }
///
/// The registration can then be performed in a single line like so:
///
/// Messenger.Default.Register(this, Receive);
///
/// The C# compiler will automatically convert that expression to a instance
/// compatible with .
/// This will also work if multiple overloads of that method are available, each handling a different
/// message type: the C# compiler will automatically pick the right one for the current message type.
/// It is also possible to register message handlers explicitly using the interface.
/// To do so, the recipient just needs to implement the interface and then call the
/// extension, which will automatically register
/// all the handlers that are declared by the recipient type. Registration for individual handlers is supported as well.
///
public interface IMessenger
{
///
/// Checks whether or not a given recipient has already been registered for a message.
///
/// The type of message to check for the given recipient.
/// The type of token to check the channel for.
/// The target recipient to check the registration for.
/// The token used to identify the target channel to check.
/// Whether or not has already been registered for the specified message.
/// Thrown if or are .
bool IsRegistered(object recipient, TToken token)
where TMessage : class
where TToken : IEquatable;
///
/// Registers a recipient for a given type of message.
///
/// The type of recipient for the message.
/// The type of message to receive.
/// The type of token to use to pick the messages to receive.
/// The recipient that will receive the messages.
/// A token used to determine the receiving channel to use.
/// The to invoke when a message is received.
/// Thrown if , or are .
/// Thrown when trying to register the same message twice.
void Register(TRecipient recipient, TToken token, MessageHandler handler)
where TRecipient : class
where TMessage : class
where TToken : IEquatable;
///
/// Unregisters a recipient from all registered messages.
///
/// The recipient to unregister.
///
/// This method will unregister the target recipient across all channels.
/// Use this method as an easy way to lose all references to a target recipient.
/// If the recipient has no registered handler, this method does nothing.
///
/// Thrown if is .
void UnregisterAll(object recipient);
///
/// Unregisters a recipient from all messages on a specific channel.
///
/// The type of token to identify what channel to unregister from.
/// The recipient to unregister.
/// The token to use to identify which handlers to unregister.
/// If the recipient has no registered handler, this method does nothing.
/// Thrown if or are .
void UnregisterAll(object recipient, TToken token)
where TToken : IEquatable;
///
/// Unregisters a recipient from messages of a given type.
///
/// The type of message to stop receiving.
/// The type of token to identify what channel to unregister from.
/// The recipient to unregister.
/// The token to use to identify which handlers to unregister.
/// If the recipient has no registered handler, this method does nothing.
/// Thrown if or are .
void Unregister(object recipient, TToken token)
where TMessage : class
where TToken : IEquatable;
///
/// Sends a message of the specified type to all registered recipients.
///
/// The type of message to send.
/// The type of token to identify what channel to use to send the message.
/// The message to send.
/// The token indicating what channel to use.
/// The message that was sent (ie. ).
/// Thrown if or are .
TMessage Send(TMessage message, TToken token)
where TMessage : class
where TToken : IEquatable;
///
/// Performs a cleanup on the current messenger.
/// Invoking this method does not unregister any of the currently registered
/// recipient, and it can be used to perform cleanup operations such as
/// trimming the internal data structures of a messenger implementation.
///
void Cleanup();
///
/// Resets the instance and unregisters all the existing recipients.
///
void Reset();
}