# 🎯 EonaCat.EventKit - The Ultimate C# Event Management Toolkit `EonaCat.EventKit` is a hybrid runtime + Roslyn analyzer library that makes subscribing/unsubscribing and managing events safer, smarter, and simpler. --- ## πŸš€ Features ### βœ… Runtime API - πŸ”„ **Subscribe/Unsubscribe to any event** dynamically - 🌐 **Subscribe to all events** of a class with optional filtering - πŸ›‘οΈ **Reentrancy-safe** handlers - πŸ’₯ **Safe execution** with built-in exception handling - πŸ“– **Track current subscriptions** - πŸ”Ž **Event forwarding** for diagnostics/logging - 🧹 **Automatic unsubscription on disposal** - 🧠 **Weak event subscriptions** for better memory management - ⏳ **Event expiry** for timed unsubscription - πŸ”„ **Retry event handling** for transient errors - πŸ”₯ **Concurrent event handling** for async operations ### 🧠 Roslyn Analyzers - ⚠️ **Detect duplicate subscriptions** - 🧹 **Detect missing unsubscriptions** - πŸ”§ **CodeFix**: auto-insert `-=` for unsubscribing --- ## πŸ“¦ Installation **Install via NuGet:** ```bash dotnet add package EonaCat.EventKit ``` ## πŸ› οΈ Usage Example Simple Event Subscription ```csharp var button = new Button(); EonaCat.EventKit.EventSubscriptionManager.Subscribe(button, "Click", (name, args) => { Console.WriteLine($"Clicked: {args}"); }); // Later EonaCat.EventKit.EventSubscriptionManager.Unsubscribe(button, "Click"); ``` **Subscribe All Events With Filter** ```csharp EonaCat.EventKit.EventSubscriptionManager.SubscribeAll( someControl, evt => evt.Name.StartsWith("On"), (name, args) => Console.WriteLine($"{name} fired!") ); ``` Concurrent Event Handling ```csharp EonaCat.EventKit.EventSubscriptionManager.SubscribeConcurrently( someControl, "Click", async (name, args) => { await SomeAsyncMethod(); Console.WriteLine($"{name} clicked asynchronously."); }); ``` **Event Subscription with Expiry** ```csharp EonaCat.EventKit.EventSubscriptionManager.SubscribeWithExpiry( someControl, "Click", (name, args) => { Console.WriteLine($"{name} clicked."); }, TimeSpan.FromSeconds(30) // Expire the subscription after 30 seconds ); ``` **Auto Unsubscribe on Dispose** ```csharp EonaCat.EventKit.EventSubscriptionManager.SubscribeWithAutoUnsubscribeOnDispose( someControl, "Click", (name, args) => { Console.WriteLine($"{name} clicked."); }); ``` πŸ› οΈ Advanced Usage Subscribe with Event Count Logging ```csharp EonaCat.EventKit.EventSubscriptionManager.SubscribeWithCountLogging( someControl, "Click", (name, args) => { Console.WriteLine($"{name} clicked."); }); ``` **Retry Logic for Event Handling** ```csharp EonaCat.EventKit.EventSubscriptionManager.SubscribeWithRetry( someControl, "Click", (name, args) => { Console.WriteLine($"{name} clicked."); }); ``` **Subscribe with Execution Context (Thread-Safe)** ```csharp EonaCat.EventKit.EventSubscriptionManager.SubscribeWithExecutionContext( someControl, "Click", (name, args) => { Console.WriteLine($"{name} clicked."); }); ``` ## πŸ”Ž Using the EventSubscriptionLogger The EventSubscriptionLogger is a useful tool for tracking and logging event subscriptions. This can help you understand the flow of event subscriptions and ensure that everything is behaving as expected. **Enabling Event Subscription Logging** To enable event subscription logging, use the EventSubscriptionLogger in combination with EventSubscriptionManager to log all subscriptions and unsubscriptions. ```csharp // Enable event subscription logging EonaCat.EventKit.EventSubscriptionLogger.Enable(); // Subscribe to an event var button = new Button(); EonaCat.EventKit.EventSubscriptionManager.Subscribe(button, "Click", (name, args) => { Console.WriteLine($"Clicked: {args}"); }); // Later, unsubscribe from the event EonaCat.EventKit.EventSubscriptionManager.Unsubscribe(button, "Click"); // Disable event subscription logging (optional) EonaCat.EventKit.EventSubscriptionLogger.Disable(); ``` Custom Event Subscription Logger You can also create a custom logger to output the subscription information in a way that fits your needs ```csharp EonaCat.EventKit.EventSubscriptionLogger.Enable(log => { // Do custom logging action: For example, log to a file or console Console.WriteLine($"Event subscribed: {log.EventName} to {log.Target}"); }); ``` ## πŸ‘€ Analyzer Diagnostics |ID| TITLE | FIX| |--|--|--| | EVT001 | Duplicate event subscription | Suggest review| | EVT002 | Missing event unsubscription | Auto-fix in code| ## 🧹 Memory Management Features ##### - 🧹 Automatic unsubscription on disposal to prevent memory leaks. ##### - 🧠 Weak event subscriptions to help with garbage collection. ##### - ⏳ Event expiry to automatically unsubscribe after a specified duration. ##### - πŸ”„ Retry logic for transient errors during event handling. ##### - πŸ”₯ Concurrent event handling for async operations. ##### - 🧠 Weak event subscriptions to prevent memory leaks when the target object is no longer referenced. ##### - πŸ’‘ Reentrancy-safe handling to avoid recursive event triggering during handler execution. ## βš™οΈ Customization Options **SubscribeOptions** - ReentrancySafe : Ensures handlers aren't invoked while already executing for the same event. - UseWeakReference: Enables weak references for event subscriptions to help with garbage collection. - HandleExceptions: Configures whether exceptions in event handlers should be logged or handled silently. **Example** ```csharp EonaCat.EventKit.EventSubscriptionManager.Subscribe( someControl, "Click", (name, args) => { Console.WriteLine($"Clicked: {args}"); }, new SubscribeOptions { ReentrancySafe = true, UseWeakReference = true }); ``` ## πŸ§‘β€πŸ’» Subscribing to Events in Regular Classes EonaCat.EventKit isn't limited to UI controls; you can subscribe to events in regular classes that define events as well. **Example with a Custom Class (Non-Control)** Let’s create a class MyCustomClass that has a few events. We'll use the source generator to generate subscription and unsubscription methods, and then use them in the same way. **Step 1: Define a Custom Class with Events** ```csharp public class MyCustomClass { // Define events public event EventHandler SomeEvent; public event EventHandler MessageEvent; // Methods to fire events public void TriggerSomeEvent() { SomeEvent?.Invoke(this, EventArgs.Empty); } public void TriggerMessageEvent(string message) { MessageEvent?.Invoke(this, message); } } ``` **Step 2: Generated Subscription Code** After running the EventSubscriptionSourceGenerator, you would get a generated class MyCustomClassEventSubscriptions, which will contain the subscription and unsubscription methods. Here's what the generated code would look like: ```csharp namespace GeneratedEventSubscriptions { public static class MyCustomClassEventSubscriptions { public static void Subscribe() { // Subscribing to events EonaCat.EventKit.EventSubscriptionManager.SubscribeWeak(MyCustomClass.Instance, "SomeEvent", GeneratedEventHandler_SomeEventHandler); EonaCat.EventKit.EventSubscriptionManager.SubscribeWeak(MyCustomClass.Instance, "MessageEvent", GeneratedEventHandler_MessageEventHandler); } public static void Unsubscribe() { // Unsubscribing from events EonaCat.EventKit.EventSubscriptionManager.Unsubscribe(MyCustomClass.Instance, "SomeEvent"); EonaCat.EventKit.EventSubscriptionManager.Unsubscribe(MyCustomClass.Instance, "MessageEvent"); } // Event Handlers private static void GeneratedEventHandler_SomeEventHandler(object sender, EventArgs args) { Console.WriteLine("SomeEvent triggered."); } private static void GeneratedEventHandler_MessageEventHandler(object sender, string message) { Console.WriteLine($"MessageEvent triggered with message: {message}"); } } } ``` **Step 3: Using the Subscription and Unsubscription in Code** Now, you can use the generated subscription and unsubscription methods just like before but with a regular class instead of a control. Here’s how to use it in your program: ```csharp using System; using GeneratedEventSubscriptions; // Import the generated namespace class Program { static void Main(string[] args) { // Create instance of the custom class var myClass = new MyCustomClass(); // Subscribe to events MyCustomClassEventSubscriptions.Subscribe(); // Trigger events myClass.TriggerSomeEvent(); // Should trigger SomeEvent handler myClass.TriggerMessageEvent("Hello, World!"); // Should trigger MessageEvent handler // Optionally, unsubscribe from events MyCustomClassEventSubscriptions.Unsubscribe(); // Trigger events again after unsubscription (no output as it is unsubscribed) myClass.TriggerSomeEvent(); myClass.TriggerMessageEvent("Goodbye!"); // No output } } ``` ## πŸ”„ Conclusion EonaCat.EventKit offers a flexible and powerful event management toolkit that works seamlessly with both UI controls and regular classes. Whether you're handling events in UI elements or business logic classes, the toolkit provides robust features like subscription management, weak references, automatic unsubscription, and even retry logic for transient errors.