EonaCat.EventKit is a hybrid runtime + Roslyn analyzer library that makes subscribing/unsubscribing and managing events safer, smarter, and simpler. https://EonaCat.com
Go to file
EonaCat 4612c852eb Initial version 2025-04-04 20:56:24 +02:00
EonaCat.EventKit Initial version 2025-04-04 20:56:24 +02:00
.gitignore Initial version 2025-04-04 20:56:24 +02:00
EonaCat.EventKit.sln Initial version 2025-04-04 20:56:24 +02:00
LICENSE Initial version 2025-04-04 20:56:24 +02:00
README.md Initial version 2025-04-04 20:56:24 +02:00
icon.png Initial version 2025-04-04 20:56:24 +02:00

README.md

🎯 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:

dotnet add package EonaCat.EventKit

🛠️ Usage Example

Simple Event Subscription

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

EonaCat.EventKit.EventSubscriptionManager.SubscribeAll(
    someControl,
    evt => evt.Name.StartsWith("On"),
    (name, args) => Console.WriteLine($"{name} fired!")
);

Concurrent Event Handling

EonaCat.EventKit.EventSubscriptionManager.SubscribeConcurrently(
    someControl,
    "Click",
    async (name, args) =>
    {
        await SomeAsyncMethod();
        Console.WriteLine($"{name} clicked asynchronously.");
    });

Event Subscription with Expiry

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

EonaCat.EventKit.EventSubscriptionManager.SubscribeWithAutoUnsubscribeOnDispose(
    someControl,
    "Click",
    (name, args) =>
    {
        Console.WriteLine($"{name} clicked.");
    });

🛠️ Advanced Usage

Subscribe with Event Count Logging

EonaCat.EventKit.EventSubscriptionManager.SubscribeWithCountLogging(
    someControl,
    "Click",
    (name, args) =>
    {
        Console.WriteLine($"{name} clicked.");
    });

Retry Logic for Event Handling

EonaCat.EventKit.EventSubscriptionManager.SubscribeWithRetry(
    someControl,
    "Click",
    (name, args) =>
    {
        Console.WriteLine($"{name} clicked.");
    });

Subscribe with Execution Context (Thread-Safe)

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.

// 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

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

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) Lets 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

public class MyCustomClass
{
    // Define events
    public event EventHandler SomeEvent;
    public event EventHandler<string> 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:

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. Heres how to use it in your program:

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.