Generating source code for actors in C#.
This is how you can use ActorSrcGen .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ActorSrcGen" Version="1.1.2" />
<PackageReference Include="ActorSrcGen.Abstractions" Version="1.1.2" />
<PackageReference Include="Gridsum.DataflowEx" Version="2.0.0" />
</ItemGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
</Project>
The code that you will use is
// See https://aka.ms/new-console-template for more information
using ActorDemo;
using Gridsum.DataflowEx;
Person person = new Person { Name = "Andrei Ignat" };
DayWorkflow dayAndreiIgnat = new ();
var input = dayAndreiIgnat.InputBlock;
//async
await dayAndreiIgnat.SendAsync(person);
//sync
while (dayAndreiIgnat.Call(person))
{
await Task.Delay(100);
}
Console.WriteLine("Done");
Console.ReadLine();
using ActorSrcGen;
using System.Diagnostics.Metrics;
namespace ActorDemo;
[Actor]
partial class DayWorkflow
{
[FirstStep("StartDay")]
//[Receiver]
[NextStep(nameof(WashFace))]
[NextStep(nameof(LogMessage))]
public async Task<Person> StartDay(Person p)
{
await Task.Delay(1000 );
return p;
}
[Step]
[NextStep(nameof(LogMessage))]
[NextStep(nameof(Eat))]
public async Task<Person> WashFace(Person p)
{
await Task.Delay(1000);
return p;
}
[Step]
[NextStep(nameof(LogMessage))]
[NextStep(nameof(Sleep))]
public async Task<Person> Eat(Person p)
{
await Task.Delay(1000);
return p;
}
[NextStep(nameof(LogMessage))]
public async Task<int> Sleep(Person p)
{
await Task.Delay(1000);
return p.Name.Length;
}
[LastStep]
public void LogMessage(Person x)
{
Console.WriteLine("Incoming Message: " + x?.Name);
}
}
namespace ActorDemo;
public class Person
{
public string Name { get; set; }
}
The code that is generated is
// Generated on 2024-06-02
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS0108 // hides inherited member.
using ActorSrcGen;
using System.Diagnostics.Metrics;
namespace ActorDemo;
using System.Threading.Tasks.Dataflow;
using Gridsum.DataflowEx;
public partial class DayWorkflow : Dataflow<Person>, IActor<Person>
{
public DayWorkflow() : base(DataflowOptions.Default)
{
_LogMessage = new ActionBlock<Person>( (Person x) => {
try
{
LogMessage(x);
}catch{}
},
new ExecutionDataflowBlockOptions() {
BoundedCapacity = 5,
MaxDegreeOfParallelism = 8
});
RegisterChild(_LogMessage);
_Eat = new TransformManyBlock<Person,Person>( async (Person x) => {
var result = new List<Person>();
try
{
var newValue = await Eat(x);
result.Add(newValue);
}catch{}
return result;
},
new ExecutionDataflowBlockOptions() {
BoundedCapacity = 5,
MaxDegreeOfParallelism = 8
});
RegisterChild(_Eat);
_EatBC = new BroadcastBlock<Person>( (Person x) => x,
new ExecutionDataflowBlockOptions() {
BoundedCapacity = 5,
MaxDegreeOfParallelism = 8
});
RegisterChild(_EatBC);
_WashFace = new TransformManyBlock<Person,Person>( async (Person x) => {
var result = new List<Person>();
try
{
var newValue = await WashFace(x);
result.Add(newValue);
}catch{}
return result;
},
new ExecutionDataflowBlockOptions() {
BoundedCapacity = 5,
MaxDegreeOfParallelism = 8
});
RegisterChild(_WashFace);
_WashFaceBC = new BroadcastBlock<Person>( (Person x) => x,
new ExecutionDataflowBlockOptions() {
BoundedCapacity = 5,
MaxDegreeOfParallelism = 8
});
RegisterChild(_WashFaceBC);
_StartDay = new TransformManyBlock<Person,Person>( async (Person x) => {
var result = new List<Person>();
try
{
var newValue = await StartDay(x);
result.Add(newValue);
}catch{}
return result;
},
new ExecutionDataflowBlockOptions() {
BoundedCapacity = 5,
MaxDegreeOfParallelism = 8
});
RegisterChild(_StartDay);
_StartDayBC = new BroadcastBlock<Person>( (Person x) => x,
new ExecutionDataflowBlockOptions() {
BoundedCapacity = 5,
MaxDegreeOfParallelism = 8
});
RegisterChild(_StartDayBC);
_Eat.LinkTo(_EatBC, new DataflowLinkOptions { PropagateCompletion = true });
_EatBC.LinkTo(_LogMessage, new DataflowLinkOptions { PropagateCompletion = true });
_WashFace.LinkTo(_WashFaceBC, new DataflowLinkOptions { PropagateCompletion = true });
_WashFaceBC.LinkTo(_LogMessage, new DataflowLinkOptions { PropagateCompletion = true });
_WashFaceBC.LinkTo(_Eat, new DataflowLinkOptions { PropagateCompletion = true });
_StartDay.LinkTo(_StartDayBC, new DataflowLinkOptions { PropagateCompletion = true });
_StartDayBC.LinkTo(_LogMessage, new DataflowLinkOptions { PropagateCompletion = true });
_StartDayBC.LinkTo(_WashFace, new DataflowLinkOptions { PropagateCompletion = true });
}
ActionBlock<Person> _LogMessage;
TransformManyBlock<Person,Person> _Eat;
BroadcastBlock<Person> _EatBC;
TransformManyBlock<Person,Person> _WashFace;
BroadcastBlock<Person> _WashFaceBC;
TransformManyBlock<Person,Person> _StartDay;
BroadcastBlock<Person> _StartDayBC;
public override ITargetBlock<Person> InputBlock { get => _StartDay; }
public bool Call(Person input)
=> InputBlock.Post(input);
public async Task<bool> Cast(Person input)
=> await InputBlock.SendAsync(input);
}
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/ActorSrcGen