diff --git a/src/core/Akka.TestKit/TestKitBase_ActorOf.cs b/src/core/Akka.TestKit/TestKitBase_ActorOf.cs index 15ef754b4db..a14f1a7e4c9 100644 --- a/src/core/Akka.TestKit/TestKitBase_ActorOf.cs +++ b/src/core/Akka.TestKit/TestKitBase_ActorOf.cs @@ -6,7 +6,6 @@ //----------------------------------------------------------------------- using System; -using System.Linq.Expressions; using Akka.Actor; using Akka.Actor.Dsl; @@ -71,7 +70,7 @@ public IActorRef ActorOf(Props props, string name) /// The type of the actor. /// An expression that calls the constructor of /// TBD - public IActorRef ActorOf(Expression> factory) where TActor : ActorBase + public IActorRef ActorOf(Func factory) where TActor : ActorBase { return Sys.ActorOf(Props.Create(factory), null); } @@ -87,7 +86,7 @@ public IActorRef ActorOf(Expression> factory) where TActor /// An expression that calls the constructor of /// The name of the actor. /// TBD - public IActorRef ActorOf(Expression> factory, string name) where TActor : ActorBase + public IActorRef ActorOf(Func factory, string name) where TActor : ActorBase { return Sys.ActorOf(Props.Create(factory), name); } @@ -201,7 +200,7 @@ public TestActorRef ActorOfAsTestActorRef(Props props, string na /// The supervisor /// Optional: The name. /// TBD - public TestActorRef ActorOfAsTestActorRef(Expression> factory, IActorRef supervisor, string name = null) where TActor : ActorBase + public TestActorRef ActorOfAsTestActorRef(Func factory, IActorRef supervisor, string name = null) where TActor : ActorBase { return new TestActorRef(Sys, Props.Create(factory), supervisor, name); } @@ -218,7 +217,7 @@ public TestActorRef ActorOfAsTestActorRef(ExpressionAn expression that calls the constructor of /// Optional: The name. /// TBD - public TestActorRef ActorOfAsTestActorRef(Expression> factory, string name = null) where TActor : ActorBase + public TestActorRef ActorOfAsTestActorRef(Func factory, string name = null) where TActor : ActorBase { return new TestActorRef(Sys, Props.Create(factory), NoSupervisor, name); } @@ -333,7 +332,7 @@ public TestFSMRef ActorOfAsTestFSMRefOptional: The name. /// Optional: If set to true logs state changes of the FSM as Debug messages. Default is false. /// TBD - public TestFSMRef ActorOfAsTestFSMRef(Expression> factory, IActorRef supervisor, string name = null, bool withLogging = false) + public TestFSMRef ActorOfAsTestFSMRef(Func factory, IActorRef supervisor, string name = null, bool withLogging = false) where TFsmActor : FSM { return new TestFSMRef(Sys, Props.Create(factory), supervisor, name, withLogging); @@ -351,7 +350,7 @@ public TestFSMRef ActorOfAsTestFSMRefOptional: The name. /// Optional: If set to true logs state changes of the FSM as Debug messages. Default is false. /// TBD - public TestFSMRef ActorOfAsTestFSMRef(Expression> factory, string name = null, bool withLogging = false) + public TestFSMRef ActorOfAsTestFSMRef(Func factory, string name = null, bool withLogging = false) where TFsmActor : FSM { return new TestFSMRef(Sys, Props.Create(factory), NoSupervisor, name, withLogging); diff --git a/src/core/Akka/Actor/Props.cs b/src/core/Akka/Actor/Props.cs index cf86531a0fe..cb88b9db1fe 100644 --- a/src/core/Akka/Actor/Props.cs +++ b/src/core/Akka/Actor/Props.cs @@ -1,4 +1,4 @@ -//----------------------------------------------------------------------- +//----------------------------------------------------------------------- // // Copyright (C) 2009-2022 Lightbend Inc. // Copyright (C) 2013-2025 .NET Foundation @@ -8,13 +8,9 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; -using Akka.Configuration; using Akka.Dispatch; using Akka.Routing; using Akka.Util; -using Akka.Util.Internal; -using Akka.Util.Reflection; using Newtonsoft.Json; namespace Akka.Actor @@ -46,8 +42,6 @@ public class Props : IEquatable, ISurrogated /// /// public static readonly Props None = null; - private Type _inputType; - private Type _outputType; private readonly IIndirectActorProducer _producer; /// @@ -163,13 +157,12 @@ public Props(Deploy deploy, Type type, IEnumerable args) /// The arguments needed to create the actor. /// This exception is thrown if is an unknown actor producer. public Props(Deploy deploy, Type type, params object[] args) -#pragma warning disable CS0618 // Type or member is obsolete - : this(CreateProducer(type, args), deploy, args) // have to preserve the "CreateProducer" call here to preserve backwards compat with Akka.DI.Core -#pragma warning restore CS0618 // Type or member is obsolete + : this(new ActivatorProducer(type, args), deploy, args) { } + /// /// Initializes a new instance of the class using a specified . /// @@ -182,7 +175,6 @@ public Props(Deploy deploy, Type type, params object[] args) internal Props(IIndirectActorProducer producer, Deploy deploy, params object[] args) { Deploy = deploy; - _inputType = producer.ActorType; Arguments = args ?? NoArgs; _producer = producer; } @@ -195,9 +187,7 @@ public Type Type { get { - if (_outputType == null) _outputType = _producer.ActorType; - - return _outputType; + return _producer.ActorType; } } @@ -225,9 +215,8 @@ public string Dispatcher /// public string TypeName { - get => _inputType.AssemblyQualifiedName; - //for serialization - private set => _inputType = Type.GetType(value); + get => _producer.ActorType.AssemblyQualifiedName; + //private set => _producer.ActorType = Type.GetType(value); } /// @@ -283,7 +272,7 @@ public ISurrogate ToSurrogate(ActorSystem system) private bool CompareInputType(Props other) { - return _inputType == other._inputType; + return _producer.ActorType == other._producer.ActorType; } private bool CompareDeploy(Props other) @@ -328,7 +317,6 @@ public override bool Equals(object obj) return Equals((Props)obj); } - public override int GetHashCode() { unchecked @@ -336,7 +324,7 @@ public override int GetHashCode() var hashCode = Deploy != null ? Deploy.GetHashCode() : 0; // hashCode = (hashCode*397) ^ (SupervisorStrategy != null ? SupervisorStrategy.GetHashCode() : 0); // hashCode = (hashCode*397) ^ (Arguments != null ? Arguments.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (_inputType != null ? _inputType.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (_producer.ActorType != null ? _producer.ActorType.GetHashCode() : 0); return hashCode; } } @@ -349,53 +337,30 @@ public override int GetHashCode() /// Optional: The supervisor strategy used to manage the actor. /// The newly created . /// The create function must be a 'new T (args)' expression - public static Props Create(Expression> factory, - SupervisorStrategy supervisorStrategy = null) where TActor : ActorBase + public static Props Create(Func factory, SupervisorStrategy supervisorStrategy = null) where TActor : ActorBase { - if (factory.Body is UnaryExpression) - return new DynamicProps(factory.Compile()); - - var newExpression = factory.Body.AsInstanceOf(); - if (newExpression == null) - throw new ArgumentException("The create function must be a 'new T (args)' expression"); - - var args = newExpression.Arguments.Count > 0 ? newExpression.GetArguments() : NoArgs; - - return new Props(new ActivatorProducer(typeof(TActor), args), DefaultDeploy, args){ SupervisorStrategy = supervisorStrategy }; + return new Props(new FactoryProducer(factory), DefaultDeploy, NoArgs) { SupervisorStrategy = supervisorStrategy }; } /// /// Creates an actor using the given arguments. /// /// The type of the actor to create. - /// The arguments needed to create the actor. - /// The newly created . - public static Props Create(params object[] args) where TActor : ActorBase - { - return new Props(new ActivatorProducer(typeof(TActor), args), DefaultDeploy, args); - } - - /// - /// Creates an actor using a specified actor producer. - /// - /// The type of producer used to create the actor. - /// The arguments needed to create the actor. /// The newly created . - [Obsolete("Do not use this method. Call CreateBy(IIndirectActorProducer, params object[] args) instead")] - public static Props CreateBy(params object[] args) where TProducer : class, IIndirectActorProducer + public static Props Create() where TActor : ActorBase, new() { - return new Props(typeof(TProducer), args); + return new Props(new FactoryProducer(() => new TActor()), DefaultDeploy, NoArgs); } /// - /// Creates an actor using a specified actor producer. + /// Creates an actor using the given arguments. /// - /// The actor producer that will be used to create the underlying actor.. + /// The type of the actor to create. /// The arguments needed to create the actor. /// The newly created . - public static Props CreateBy(IIndirectActorProducer producer, params object[] args) + public static Props Create(params object[] args) where TActor : ActorBase { - return new Props(producer, DefaultDeploy, args); + return new Props(new ActivatorProducer(typeof(TActor), args), DefaultDeploy, args); } /// @@ -406,7 +371,7 @@ public static Props CreateBy(IIndirectActorProducer producer, params object[] ar /// The newly created . public static Props Create(SupervisorStrategy supervisorStrategy) where TActor : ActorBase, new() { - return new Props(new ActivatorProducer(typeof(TActor), NoArgs), DefaultDeploy, NoArgs){ SupervisorStrategy = supervisorStrategy }; + return new Props(new FactoryProducer(() => new TActor()), DefaultDeploy, NoArgs) { SupervisorStrategy = supervisorStrategy }; } /// @@ -424,6 +389,29 @@ public static Props Create(Type type, params object[] args) return new Props(type, args); } + /// + /// Creates an actor using a specified actor producer. + /// + /// The type of producer used to create the actor. + /// The arguments needed to create the actor. + /// The newly created . + [Obsolete("Do not use this method. Call CreateBy(IIndirectActorProducer, params object[] args) instead")] + public static Props CreateBy(params object[] args) where TProducer : class, IIndirectActorProducer + { + return new Props(typeof(TProducer), args); + } + + /// + /// Creates an actor using a specified actor producer. + /// + /// The actor producer that will be used to create the underlying actor.. + /// The arguments needed to create the actor. + /// The newly created . + public static Props CreateBy(IIndirectActorProducer producer, params object[] args) + { + return new Props(producer, DefaultDeploy, args); + } + /// /// Creates a new with a given . /// @@ -468,7 +456,7 @@ public Props WithRouter(RouterConfig routerConfig) copy.Deploy = Deploy.WithRouterConfig(routerConfig); return copy; } - + /// /// Creates a new with a given stash size. /// @@ -499,12 +487,13 @@ public Props WithStashCapacity(int stashCapacity) public Props WithDeploy(Deploy deploy) { var copy = Copy(); - var original = copy.Deploy; + //var original = copy.Deploy; // TODO: this is a hack designed to preserve explicit router deployments https://github.com/akkadotnet/akka.net/issues/546 // in reality, we should be able to do copy.Deploy = deploy.WithFallback(copy.Deploy); but that blows up at the moment // - Aaron Stannard copy.Deploy = deploy.WithFallback(copy.Deploy); + //if (!(original.RouterConfig is NoRouter || original.RouterConfig is FromConfig) && deploy.RouterConfig is NoRouter) //{ // copy.Deploy = deploy.WithFallback(copy.Deploy); @@ -555,17 +544,13 @@ public Props WithSupervisorStrategy(SupervisorStrategy supervisorStrategy) /// The newly created actor public virtual ActorBase NewActor() { - var type = Type; - var arguments = Arguments; try { return _producer.Produce(); } catch (Exception e) { - throw new TypeLoadException( - $"Error while creating actor instance of type {type} with {arguments.Length} args: ({StringFormat.SafeJoin(",", arguments)})", - e); + throw new TypeLoadException($"Error while creating actor instance of type {Type} with {Arguments.Length} args: ({StringFormat.SafeJoin(",", Arguments)})", e); } } @@ -578,23 +563,6 @@ protected virtual Props Copy() return new Props(_producer, Deploy, Arguments) { SupervisorStrategy = SupervisorStrategy }; } - [Obsolete("we should not be calling this method. Pass in an explicit IIndirectActorProducer reference instead.")] - private static IIndirectActorProducer CreateProducer(Type type, object[] args) - { - if (type == null) return DefaultProducer.Instance; - - if (typeof(IIndirectActorProducer).IsAssignableFrom(type)) - return Activator.CreateInstance(type, args).AsInstanceOf(); - - if (typeof(ActorBase).IsAssignableFrom(type)) return new ActivatorProducer(type, args); - - throw new ArgumentException($"Unknown actor producer [{type.FullName}]", nameof(type)); - } - - /// - /// Signals the producer that it can release its reference to the actor. - /// - /// The actor to release internal void Release(ActorBase actor) { try @@ -655,26 +623,6 @@ protected override void OnReceive(object message) } } - private class DefaultProducer : IIndirectActorProducer - { - private DefaultProducer(){} - - public static readonly DefaultProducer Instance = new(); - - public ActorBase Produce() - { - throw new InvalidOperationException("No actor producer specified!"); - } - - public Type ActorType => typeof(ActorBase); - - - public void Release(ActorBase actor) - { - actor = null; - } - } - private class ActivatorProducer : IIndirectActorProducer { private readonly object[] _args; @@ -687,23 +635,22 @@ public ActivatorProducer(Type actorType, object[] args) public ActorBase Produce() { - return Activator.CreateInstance(ActorType, _args).AsInstanceOf(); + return (ActorBase)Activator.CreateInstance(ActorType, _args); } public Type ActorType { get; } - public void Release(ActorBase actor) { actor = null; } } - private class FactoryConsumer : IIndirectActorProducer where TActor : ActorBase + private class FactoryProducer : IIndirectActorProducer where TActor : ActorBase { private readonly Func _factory; - public FactoryConsumer(Func factory) + public FactoryProducer(Func factory) { _factory = factory; } @@ -715,7 +662,6 @@ public ActorBase Produce() public Type ActorType => typeof(TActor); - public void Release(ActorBase actor) { actor = null; @@ -751,7 +697,7 @@ public override ActorBase NewActor() /// The type of the actor to create. internal class DynamicProps : Props where TActor : ActorBase { - private readonly Func invoker; + private readonly Func _invoker; /// /// Initializes a new instance of the class. @@ -760,7 +706,7 @@ internal class DynamicProps : Props where TActor : ActorBase public DynamicProps(Func invoker) : base(typeof(TActor)) { - this.invoker = invoker; + this._invoker = invoker; } /// @@ -769,7 +715,7 @@ public DynamicProps(Func invoker) /// The actor created using the factory method. public override ActorBase NewActor() { - return invoker.Invoke(); + return _invoker.Invoke(); } #region Copy methods @@ -777,7 +723,7 @@ public override ActorBase NewActor() private DynamicProps(Props copy, Func invoker) : base(copy) { - this.invoker = invoker; + this._invoker = invoker; } /// @@ -787,7 +733,7 @@ private DynamicProps(Props copy, Func invoker) protected override Props Copy() { var initialCopy = base.Copy(); - var invokerCopy = (Func)invoker.Clone(); + var invokerCopy = (Func)_invoker.Clone(); return new DynamicProps(initialCopy, invokerCopy); } @@ -828,4 +774,4 @@ public interface IIndirectActorProducer /// The actor to release void Release(ActorBase actor); } -} +} \ No newline at end of file