FacetAPI is a flexible event/callback management library with support for reactive programming, pause/resume functionality, and state persistence. Key features include:
- Generic callback management with type safety
- Reactive callbacks that push latest state to new subscribers
- Pause/resume control for callbacks
- Async condition monitoring helpers
- Stasis invocation (persistent state)
Main entry point for callback management.
Methods:
public IFacetCallback<TDelegate> CreateCallback<TDelegate>(string name, bool reactive = false)
public IFacetCallback<TDelegate> Get<TDelegate>(string name)
public void PauseAll()
public void ResumeAll()Pre-built implementations for common Action signatures.
Variants:
ActionFacet<T1>ActionFacet<T1, T2>
Usage:
var callback = new ActionFacet<string>(reactive: true);
callback.Invoke("test");Core implementation of callback handling.
Key Members:
void Subscribe(TDelegate handler)
void Unsubscribe(TDelegate handler)
void StasisInvoke(params object[] parameters) // Persistent invocation
bool IsReactive { get; } // New subscribers get last value
bool IsPaused { get; }Extension methods for enhanced functionality.
Methods:
void InvokeIf<T>(this IFacetCallback<Action<T>> callback, T arg, Func<T, bool> condition)
Task WatchAndInvokeAsync<T>(/*...*/) // Async condition monitoringpublic interface IFacetCallback // Base interface
public interface IFacetCallback<TDelegate> // Generic version- When created with
reactive: true, new subscribers immediately receive:- Last
StasisInvokeparameters (if any) - Last regular invocation parameters (only if created after StasisInvoke)
- Last
StasisInvokeperforms two actions:- Stores parameters as persistent state
- Triggers normal invocation
- Subsequent subscribers receive stasis parameters immediately if:
- Callback is reactive
- Stasis value exists
- Control callback triggering at individual or global level:
// Per callback
callback.Pause();
callback.Resume();
// Global
api.PauseAll();
api.ResumeAll();var api = new FacetApi();
var callback = api.CreateCallback<Action<string>>("message", reactive: true);
// Subscribe
callback.Subscribe(msg => Console.WriteLine($"Received: {msg}"));
// Invoke
callback.Invoke("Hello World");
// Stasis invocation
callback.StasisInvoke("Persistent message");await callback.WatchAndInvokeAsync(
arg: "server_up",
condition: () => CheckServerStatus(),
checkInterval: TimeSpan.FromSeconds(5)
);callback.InvokeIf(42, x => x > 0); // Only invokes if value is positive-
Parameter Matching:
- Ensure invocation parameters match delegate type signatures
- Mismatches will throw
ArgumentExceptionduring DynamicInvoke
-
Thread Safety:
- Uses
ToArray()in Invoke for thread-safe enumeration - Concurrent modifications during invocation are safe but might not be atomic
- Uses
-
Performance:
- Prefer strongly-typed ActionFacet over
FacetDelegatefor better performance DynamicInvokehas overhead compared to direct invocation
- Prefer strongly-typed ActionFacet over
-
Lifetime Management:
- Always unsubscribe handlers when no longer needed
- Use
UnsubscribeAll()to clear all handlers
- Naming: Use descriptive names when creating callbacks
- Reactive Mode: Enable for stateful components that need latest values
- Stasis: Use for initialization data or important persistent state
- Extensions: Leverage
WatchAndInvokeAsyncfor polling scenarios