Tenekon.Coroutines
0.1.0-preview.4
Prefix Reserved
dotnet add package Tenekon.Coroutines --version 0.1.0-preview.4
NuGet\Install-Package Tenekon.Coroutines -Version 0.1.0-preview.4
<PackageReference Include="Tenekon.Coroutines" Version="0.1.0-preview.4" />
<PackageVersion Include="Tenekon.Coroutines" Version="0.1.0-preview.4" />
<PackageReference Include="Tenekon.Coroutines" />
paket add Tenekon.Coroutines --version 0.1.0-preview.4
#r "nuget: Tenekon.Coroutines, 0.1.0-preview.4"
#:package Tenekon.Coroutines@0.1.0-preview.4
#addin nuget:?package=Tenekon.Coroutines&version=0.1.0-preview.4&prerelease
#tool nuget:?package=Tenekon.Coroutines&version=0.1.0-preview.4&prerelease
Tenekon.Coroutines

Write C# async-await coroutines in a Redux-Saga fashion and let them behave like JavaScript generators
You found a bug, have ideas or just want to talk? Join the Tenekon Community, start a discussion or open an issue.
Tenekon.Coroutines key facts on a glance
- 100% compatible to
Task/ValueTask- Almost as fast as
ValueTask
- Almost as fast as
- Async iterators: make coroutines iterable
- Each suspension point allows to clone the async iterator
- Fully AOT-compatible
- Highly extendible via new yielders and/or custom coroutine context
- Child coroutines inherit context of their parents: reduce explicit dependency injection
Installation
Minimum requirements
- Target framework that at least supports NET Standard 2.1 or .NET 6.0
Package Manager
Install-Package Tenekon.Coroutines -Version <type version here>
.NET CLI
dotnet add package Tenekon.Coroutines --version <type version here>
Quick start guide
Simple Coroutine: Hello World
using static Tenekon.Coroutines.Yielders;
await Coroutine.Start(async () => {
await Call(Console.WriteLine, "Hello world");
});
// or
await Func<Coroutine>(async () => {
await Call(Console.WriteLine, "Hello world");
});
// Outputs:
// Hello world
Advanced Coroutine: Parallelism
await Coroutine.Start(async () =>
{
var t1 = await Coroutine.Factory.StartNew(async () =>
{
Thread.Sleep(3000);
Console.WriteLine(DateTime.UtcNow - Process.GetCurrentProcess().StartTime.ToUniversalTime() + ": Finished");
});
var t2 = await Coroutine.Factory.StartNew(async () =>
{
Thread.Sleep(3000);
Console.WriteLine(DateTime.UtcNow - Process.GetCurrentProcess().StartTime.ToUniversalTime() + ": Finished");
});
await Task.WhenAll(t1.AsTask(), t2.AsTask());
});
// 00:00:03.0317613: Finished
// 00:00:03.0317757: Finished
Simple AsyncIterator: Iterator
using static Tenekon.Coroutines.Yielders;
using static Tenekon.Coroutines.Yielders.Arguments;
var iterator = AsyncIterator.Create(async () => {
await Call(Console.WriteLine, "Hello world");
});
while (await iterator.MoveNextAsync()) {
Console.WriteLine(((CallArgument<string>)iterator.Current).Closure);
}
// Outputs:
// Hello world
// Hello world
Advanced AsyncIterator: Iterator, Replace Current
using static Tenekon.Coroutines.Yielders;
using static Tenekon.Coroutines.Yielders.Arguments;
var iterator = AsyncIterator.Create(async () => {
await Call(Console.WriteLine, "Hello world");
});
while (await iterator.MoveNextAsync()) {
Console.WriteLine(((CallArgument<string>)iterator.Current).Closure);
iterator.Current = new CallArgument<string>(Console.WriteLine, "Hello iterator")
}
// Outputs:
// Hello world
// Hello iterator
Advanced AsyncIterator: Iterator, Yield Assign
using static Tenekon.Coroutines.Iterator.Yielders;
using static Tenekon.Coroutines.Iterator.Yielders.Arguments;
var iterator = AsyncIterator.Create(async () => {
Console.WriteLine(await Exchange("Hello world"));
});
while (await iterator.MoveNextAsync()) {
Console.WriteLine(((ExchangeArgument<string>)iterator.Current).Value);
iterator.YieldAssign("Hello iterator");
}
// Outputs:
// Hello world
// Hello iterator
Quick references
Yielders are the equivalent to effects in Redux-Saga.
In the following are all available Yielders classes and their contained yielders listed.
Tenekon.Coroutines.Coroutine
The yielding components of Coroutine are designed to align with the functionality of Task.
Tenekon.Coroutines.Coroutine.Yield
Use Yield to instruct the coroutine to suspend and resume immediatelly. In the underlying code, Task.Yield() is used.
| Yielder | Signature |
|---|---|
Yield |
Coroutine Coroutine Yield() |
Tenekon.Coroutines.Coroutine.Run
The Coroutine.Run yielder is the equivalent to Task.Run
| Yielder | Signature |
|---|---|
Coroutine.Run |
Coroutine<CoroutineAwaitable> Run(Func<Coroutine> provider, CancellationToken cancellationToken) |
Coroutine.Run |
Coroutine<CoroutineAwaitable> Run(Func<Coroutine> provider) |
Coroutine.Run |
Coroutine<CoroutineAwaitable> Run<TClosure>(Func<TClosure, Coroutine> provider, TClosure closure, CancellationToken cancellationToken) |
Coroutine.Run |
Coroutine<CoroutineAwaitable> Run<TClosure>(Func<TClosure, Coroutine> provider, TClosure closure) |
Coroutine.Run |
Coroutine<CoroutineAwaitable<TResult>> Run<TResult>(Func<Coroutine<TResult>> provider, CancellationToken cancellationToken) |
Coroutine.Run |
Coroutine<CoroutineAwaitable<TResult>> Run<TResult>(Func<Coroutine<TResult>> provider) |
Coroutine.Run |
Coroutine<CoroutineAwaitable<TResult>> Run<TClosure, TResult>(Func<TClosure, Coroutine<TResult>> provider, TClosure closure, CancellationToken cancellationToken) |
Coroutine.Run |
Coroutine<CoroutineAwaitable<TResult>> Run<TClosure, TResult>(Func<TClosure, Coroutine<TResult>> provider, TClosure closure) |
Tenekon.Coroutines.Coroutine.Run
The Coroutine.Factory.StartNew yielder is the equivalent to Task.Factory.StartNew
| Yielder | Signature |
|---|---|
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable> StartNew(Func<Coroutine> provider, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable> StartNew(Func<Coroutine> provider, CancellationToken cancellationToken) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable> StartNew(Func<Coroutine> provider, TaskCreationOptions creationOptions) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable> StartNew(Func<Coroutine> provider) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable> StartNew<TClosure>(Func<TClosure, Coroutine> provider, TClosure closure, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable> StartNew<TClosure>(Func<TClosure, Coroutine> provider, TClosure closure, CancellationToken cancellationToken) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable> StartNew<TClosure>(Func<TClosure, Coroutine> provider, TClosure closure, TaskCreationOptions creationOptions) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable> StartNew<TClosure>(Func<TClosure, Coroutine> provider, TClosure closure) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable<TResult>> StartNew<TResult>(Func<Coroutine<TResult>> provider, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable<TResult>> StartNew<TResult>(Func<Coroutine<TResult>> provider, CancellationToken cancellationToken) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable<TResult>> StartNew<TResult>(Func<Coroutine<TResult>> provider, TaskCreationOptions creationOptions) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable<TResult>> StartNew<TResult>(Func<Coroutine<TResult>> provider) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable<TResult>> StartNew<TClosure, TResult>(Func<TClosure, Coroutine<TResult>> provider, TClosure closure, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable<TResult>> StartNew<TClosure, TResult>(Func<TClosure, Coroutine<TResult>> provider, TClosure closure, CancellationToken cancellationToken) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable<TResult>> StartNew<TClosure, TResult>(Func<TClosure, Coroutine<TResult>> provider, TClosure closure, TaskCreationOptions creationOptions) |
Coroutine.Factory.StartNew |
Coroutine<CoroutineAwaitable<TResult>> StartNew<TClosure, TResult>(Func<TClosure, Coroutine<TResult>> provider, TClosure closure) |
Tenekon.Coroutines.Yielders
We recommend to make use of using static, e.g. using static Tenekon.Coroutines.Yielders.
Tenekon.Coroutines.Yielders.Call
The Call yielder is the equivalent to the call effect in Redux-Saga.
Use it to instruct the coroutine to suspend and invoke provider with optional closure. The coroutine resumes as soon as provider completed.
| Yielder | Signature |
|---|---|
Call |
Coroutine Call(Func<Coroutine> provider) |
Call |
Coroutine Call<TClosure>(Func<TClosure, Coroutine> provider, TClosure closure) |
Call |
Coroutine<TResult> Call<TResult>(Func<Coroutine<TResult>> provider) |
Call |
Coroutine<TResult> Call<TClosure, TResult>(Func<TClosure, Coroutine<TResult>> provider, TClosure closure) |
Tenekon.Coroutines.Yielders.Launch
The Launch yielder is the equivalent to the fork effect in Redux-Saga.
Use it to instruct the coroutine to suspend and invoke provider with optional closure. The coroutine resumes immediatelly, but in case coroutine returns before provider finished it will suspend as long as provider won't have completed.
| Yielder | Signature |
|---|---|
Launch |
Coroutine<CoroutineAwaitable> Launch(Func<Coroutine> provider) |
Launch |
Coroutine<CoroutineAwaitable> Launch<TClosure>(Func<TClosure, Coroutine> provider, TClosure closure) |
Launch |
Coroutine<CoroutineAwaitable<TResult>> Launch<TResult>(Func<Coroutine<TResult>> provider) |
Launch |
Coroutine<CoroutineAwaitable<TResult>> Launch<TClosure, TResult>(Func<TClosure, Coroutine<TResult>> provider, TClosure closure) |
Tenekon.Coroutines.Yielders.Spawn
The Spawn yielder is the equivalent to the spawn effect in Redux-Saga.
Use it to instruct the coroutine to suspend and invoke provider with optional closure. The coroutine resumes immediatelly, but in case coroutine returns before provider finished it will just return and provider will just continue to operate independently.
| Yielder | Signature |
|---|---|
Spawn |
Coroutine<CoroutineAwaitable> Spawn(Func<Coroutine> provider) |
Spawn |
Coroutine<CoroutineAwaitable> Spawn<TClosure>(Func<TClosure, Coroutine> provider, TClosure closure) |
Spawn |
Coroutine<CoroutineAwaitable<TResult>> Spawn<TResult>(Func<Coroutine<TResult>> provider) |
Spawn |
Coroutine<CoroutineAwaitable<TResult>> Spawn<TClosure, TResult>(Func<TClosure, Coroutine<TResult>> provider, TClosure closure) |
Tenekon.Coroutines.Yielders.Spawn
Use Throw to instruct the coroutine to suspend and let the coroutine throw exception. The coroutine resumes immediatelly and throws excpetion.
| Yielder | Signature |
|---|---|
Throw |
Coroutine Throw(Exception exception) |
Tenekon.Coroutines.Yielders.WithContext
Use WithContext to instruct the coroutine to suspend and invoke provider with additiveContext and optional closure.
| Yielder | Signature |
|---|---|
WithContext |
Coroutine WithContext(CoroutineContext additiveContext, Func<Coroutine> provider) |
WithContext |
Coroutine WithContext<TClosure>(CoroutineContext additiveContext, Func<TClosure, Coroutine> provider, TClosure closure) |
WithContext |
Coroutine<TResult> WithContext<TResult>(CoroutineContext additiveContext, Func<Coroutine<TResult>> provider) |
WithContext |
Coroutine<TResult> WithContext<TClosure, TResult>(CoroutineContext additiveContext, Func<TClosure, Coroutine<TResult>> provider, TClosure closure) |
Tenekon.Coroutines.Yielders.YieldReturn
Use YieldReturn to instruct the coroutine to suspend and resume immediatelly. Allows the coroutine middleware to get the hands on value.
| Yielder | Signature |
|---|---|
YieldReturn |
Coroutine YieldReturn<T>(T value) |
Tenekon.Coroutines.Yielders.YieldAssign
Use YieldAssign to instruct the coroutine to suspend and resume immediatelly.
Allows the coroutine middleware to get the hands on value and also to yield assign a custom value of type TAssign.
If you do not yield assign a custom value of type TAssign, then default(TAssign) is yield assigned.
| Yielder | Signature |
|---|---|
YieldAssign |
YieldAssign<TYield> Yield<TYield>(TYield value) => new(value) → Coroutine<TAssign> Assign<TAssign>() |
Tenekon.Coroutines.Yielders.Exchange
Use Exchange to instruct the coroutine to suspend and resume immediatelly. Allows the coroutine middleware to get the hands on value and exchange it.
| Yielder | Signature |
|---|---|
Exchange |
Coroutine<T> Exchange<T>(T value) |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- K4os.Hash.xxHash (>= 1.0.8)
- Microsoft.Bcl.HashCode (>= 1.1.1)
- System.Threading.Tasks.Extensions (>= 4.5.4)
-
net6.0
- K4os.Hash.xxHash (>= 1.0.8)
-
net7.0
- K4os.Hash.xxHash (>= 1.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-preview.4 | 87 | 10/6/2024 |
| 0.1.0-preview.3 | 71 | 10/6/2024 |
| 0.1.0-preview.2 | 76 | 9/26/2024 |
| 0.1.0-preview.1 | 80 | 9/26/2024 |