Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
name: ci-build

env:
DOTNET_VERSION: 9.0.x
DOTNET_VERSION: 10.0.x
REGISTRY: ghcr.io

jobs:
Expand Down
10 changes: 5 additions & 5 deletions MinimalEvents/MinimalEvents.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<AssemblyName>OpenShock.MinimalEvents</AssemblyName>
<RootNamespace>OpenShock.MinimalEvents</RootNamespace>
<TargetFrameworks>net9.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks>net10.0;netstandard2.1</TargetFrameworks>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>OpenShock.MinimalEvents</PackageId>
<Title>MinimalEvents</Title>
Expand All @@ -15,14 +15,14 @@
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/OpenShock/MinimalEvents</RepositoryUrl>
<PackageProjectUrl>https://openshock.org</PackageProjectUrl>
<LangVersion>13</LangVersion>
<LangVersion>latest</LangVersion>
<Product>MinimalEvents</Product>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>

<Version>0.0.1</Version>
<AssemblyVersion>0.0.1</AssemblyVersion>
<FileVersion>0.0.1</FileVersion>
<Version>1.0.0</Version>
<AssemblyVersion>1.0.0</AssemblyVersion>
<FileVersion>1.0.0</FileVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
3 changes: 2 additions & 1 deletion MinimalEventsTests/MinimalEventsTests.csproj
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Company>OpenShock</Company>
<AssemblyName>OpenShock.MinimalEvents.Tests</AssemblyName>
<RootNamespace>OpenShock.MinimalEvents.Tests</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
Expand Down
100 changes: 97 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,99 @@
# Minimal Events
# Minimal Events

Minimal Events is a very opinionated event library designed to be used in OpenShock projects.
Minimal Events is a very opinionated, minimal and modern event library designed to be used in OpenShock projects.

Inspired by System.Reactive (RxNET)
Inspired by [System.Reactive (Rx.NET)](https://github.com/dotnet/reactive), it provides a tiny observable-style API for subscribing to and invoking events, both synchronously and asynchronously.

## Features

- Synchronous and asynchronous events
- Optional strongly-typed event arguments
- Subscriptions are managed via `IDisposable` / `IAsyncDisposable` — dispose to unsubscribe
- Thread-safe subscribe/unsubscribe backed by immutable handler lists
- Targets `net10.0` and `netstandard2.1`

## Installation

```sh
dotnet add package OpenShock.MinimalEvents
```

## Usage

### Synchronous

```csharp
using OpenShock.MinimalEvents;

var onTick = new MinimalEvent();

using (onTick.Subscribe(() => Console.WriteLine("tick")))
{
onTick.Invoke(); // prints "tick"
}

onTick.Invoke(); // nothing — the subscription was disposed
```

### Synchronous with an argument

```csharp
var onMessage = new MinimalEvent<string>();

using var subscription = onMessage.Subscribe(msg => Console.WriteLine($"got: {msg}"));

onMessage.Invoke("hello"); // prints "got: hello"
```

### Asynchronous

```csharp
var onStarted = new AsyncMinimalEvent();

await using var subscription = await onStarted.SubscribeAsync(async () =>
{
await Task.Delay(10);
Console.WriteLine("started");
});

await onStarted.InvokeAsyncParallel(); // invokes all handlers in parallel
```

### Asynchronous with an argument

```csharp
var onValue = new AsyncMinimalEvent<int>();

await using var subscription = await onValue.SubscribeAsync(async value =>
{
await Task.Delay(10);
Console.WriteLine($"value: {value}");
});

await onValue.InvokeAsyncParallel(42);
```

Async handlers are invoked in parallel; if any handler throws, the aggregated exception is rethrown once all handlers have completed.

## Exposing events

To expose an event without letting consumers invoke it, return the matching observable interface:

- `IMinimalEventObservable` / `IMinimalEventObservable<T>`
- `IAsyncMinimalEventObservable` / `IAsyncMinimalEventObservable<T>`

```csharp
public sealed class Connection
{
private readonly AsyncMinimalEvent<string> _onMessage = new();

// Consumers can subscribe, but only Connection can invoke.
public IAsyncMinimalEventObservable<string> OnMessage => _onMessage;

internal Task RaiseAsync(string message) => _onMessage.InvokeAsyncParallel(message);
}
```

## License

[MIT](LICENSE)
5 changes: 5 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"test": {
"runner": "Microsoft.Testing.Platform"
}
}