Skip to content

Instantly share code, notes, and snippets.

@Horusiath
Last active March 29, 2022 09:38
Show Gist options
  • Save Horusiath/f5c77e043ee17e02d0311315bcde9c79 to your computer and use it in GitHub Desktop.
Save Horusiath/f5c77e043ee17e02d0311315bcde9c79 to your computer and use it in GitHub Desktop.
Typed actor refs snipped for Akka.NET
using System;
namespace Akka.Testing
{
public interface IMyMessage { }
public sealed class MessageA : IMyMessage { }
public sealed class MessageB : IMyMessage { }
public class MyActor : Actor<IMyMessage>
{
protected override void OnReceive(IMyMessage message) => message.Match()
.With<MessageA>(_ => Console.WriteLine("Received A"))
.With<MessageB>(_ => Console.WriteLine("Received B"))
.Default(Unhandled);
}
class Program
{
static void Main(string[] args)
{
using (var system = Actor.ActorSystem.Create("sys"))
{
var a = system.ActorOf(Props<IMyMessage>.Create(() => new MyActor()));
a.Tell(new MessageA());
a.Tell("error"); // doesn't compile
Console.ReadLine();
}
}
}
}
using System;
using System.Linq.Expressions;
using Akka.Actor;
using Akka.Util;
namespace Akka
{
public struct TypedRef<T> : IActorRef
{
public TypedRef(IActorRef aref) : this()
{
if (aref == null) throw new ArgumentNullException(nameof(aref), $"{this} has received null instead of {nameof(IActorRef)}");
Ref = aref;
}
public IActorRef Ref { get; }
void ICanTell.Tell(object message, IActorRef sender) => Ref.Tell(message, sender);
public void Tell(T message, IActorRef sender) => Ref.Tell(message, sender);
public void Tell(T message) => Ref.Tell(message, ActorCell.GetCurrentSelfOrNoSender());
public bool Equals(IActorRef other) =>
other is TypedRef<T> ? Ref.Equals(((TypedRef<T>)other).Ref) : Ref.Equals(other);
public int CompareTo(IActorRef other) =>
other is TypedRef<T> ? Ref.CompareTo(((TypedRef<T>)other).Ref) : Ref.CompareTo(other);
public ISurrogate ToSurrogate(ActorSystem system) => new TypeRefSurrogate<T>(Ref.ToSurrogate(system));
public int CompareTo(object obj)
{
if (obj is IActorRef) return CompareTo((IActorRef)obj);
throw new ArgumentException($"Cannot compare {obj} to {this}");
}
public ActorPath Path => Ref.Path;
public override int GetHashCode() => Ref.GetHashCode();
public override bool Equals(object obj) => obj is IActorRef && Equals((IActorRef)obj);
public override string ToString() => Ref.ToString();
}
public struct Props<T> : ISurrogated
{
public readonly Props Underlying;
public Props(Props props) : this()
{
if (props == null) throw new ArgumentNullException(nameof(props), $"{this} has received null instead of {nameof(Props)}");
this.Underlying = props;
}
public static Props<T> Create<TActor>(Expression<Func<TActor>> fac) where TActor : Actor<T>
=> new Props<T>(Props.Create(fac));
public ISurrogate ToSurrogate(ActorSystem system) => new TypedPropsSurrogate<T>(Underlying.ToSurrogate(system));
}
internal struct TypedPropsSurrogate<T> : ISurrogate
{
public readonly ISurrogate PropsSurrogate;
public TypedPropsSurrogate(ISurrogate propsSurrogate) : this()
{
PropsSurrogate = propsSurrogate;
}
public ISurrogated FromSurrogate(ActorSystem system) => new Props<T>((Props)PropsSurrogate.FromSurrogate(system));
}
internal struct TypeRefSurrogate<T> : ISurrogate
{
public readonly ISurrogate RefSurrogate;
public TypeRefSurrogate(ISurrogate refSurrogate) : this()
{
RefSurrogate = refSurrogate;
}
public ISurrogated FromSurrogate(ActorSystem system) => new TypedRef<T>((IActorRef)RefSurrogate.FromSurrogate(system));
}
public abstract class Actor<T> : UntypedActor
{
protected abstract void OnReceive(T message);
protected override void OnReceive(object message)
{
if (message is T)
OnReceive((T)message);
else Unhandled(message);
}
}
public static class TypedExtensions
{
public static TypedRef<T> ActorOf<T>(this IActorRefFactory fac, Props<T> props) =>
new TypedRef<T>(fac.ActorOf(props.Underlying));
public static TypedRef<T> ActorOf<T>(this IActorRefFactory fac, Props<T> props, string name) =>
new TypedRef<T>(fac.ActorOf(props.Underlying, name));
public static TypedRef<T> Watch<T>(this IActorContext ctx, TypedRef<T> tref)
{
ctx.Watch(tref.Ref);
return tref;
}
public static TypedRef<T> Unwatch<T>(this IActorContext ctx, TypedRef<T> tref)
{
ctx.Unwatch(tref.Ref);
return tref;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment