我想要做的是将两个 Actor (妈妈 Actor 和爸爸 Actor )传递给小 Actor 。由于使用 Actor 引用而不是 Actor 是最佳实践,因此我使用 IActorRef 为妈妈 Actor 和爸爸 Actor 使用命名参数通过 DI 注入(inject)。但我收到“mummyActor 不是唯一的”错误。知道如何解决吗?

using System;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.DI.AutoFac;
using Akka.DI.Core;
using Autofac;
using Autofac.Core;


namespace Akka.DI.AutoFac.ExampleConsole {

    public class DaddyActor : ReceiveActor {
        public DaddyActor() {
            Receive<DoneEatingMessage>(m => {
                Console.WriteLine("Kid finished eating. So what? ~ Dad");
            });
        }
    }


    public class MummyActor : ReceiveActor {
        public MummyActor() {
            Receive<DoneEatingMessage>(m => {
                Console.WriteLine("Kid finished eating. Time to clean up! ~Mummy");
            });
        }
    }

    public class KidActor : ReceiveActor {

        private IService _service;

        private IActorRef _mummyActor;
        private IActorRef _daddyActor;

        public KidActor(IService service, IActorRef mummyActor, IActorRef daddyActor) {
            this._service = service;
            this._mummyActor = mummyActor;
            this._daddyActor = daddyActor;

            Receive<EatMessage>(m=>{
                var food = service.GetFood();
                Console.WriteLine("Kid eat this food {0}", food);
                _mummyActor.Tell(new DoneEatingMessage());
            });
        }


    }

    public class EatMessage{    }
    public class DoneEatingMessage { }

    public interface IService {
        string GetFood();
    }
    public class FoodService : IService {

        public string GetFood() {
            return "banana";
        }
    }
    class Program {
        static ActorSystem _actorSystem;
        static void Main(string[] args) {

            var builder = new Autofac.ContainerBuilder();
            builder.RegisterType<FoodService>().As<IService>();
            builder.RegisterType<MummyActor>().InstancePerDependency();
            builder.RegisterType<DaddyActor>().InstancePerDependency();

            builder.Register(c => _actorSystem.ActorOf(_actorSystem.DI().Props<DaddyActor>(), "daddyActor"))
                .Named<IActorRef>("daddyActorRef")
                .AsSelf();

            builder.Register(c => _actorSystem.ActorOf(_actorSystem.DI().Props<MummyActor>(), "mummyActor"))
                .Named<IActorRef>("mummyActorRef")
                .AsSelf();



            builder.RegisterType<KidActor>()
                .WithParameter(
                  new ResolvedParameter(
                       (pi, ctx) => pi.ParameterType == typeof(MummyActor),
                       (pi, ctx) => ctx.ResolveNamed<IActorRef>("mummyActorRef")
                    )
                )
                .WithParameter(
                  new ResolvedParameter(
                       (pi, ctx) => pi.ParameterType == typeof(DaddyActor),
                       (pi, ctx) => ctx.ResolveNamed<IActorRef>("daddyActorRef")
                    )
                )
                .InstancePerDependency();

            var container = builder.Build();

            _actorSystem = ActorSystem.Create("ActorDISystem");
            var propsResolver = new AutoFacDependencyResolver(container, _actorSystem);


            var kidActorProps = _actorSystem.DI().Props<KidActor>();
            var kidActor = _actorSystem.ActorOf(kidActorProps, "kidActor");

            kidActor.Tell(new EatMessage());

            Console.WriteLine("Holah");
            Console.ReadLine();
        }
    }
}

最佳答案

问题是 MummyActor 和 DaddyActor 类型不是 IActorRef 的实例。所以在创建 KidActor 时不能使用这些类型。

我对 AutoFac 不是很熟悉,但我能够让它像这样工作:

builder.RegisterType<KidActor>()
.WithParameter(
  new ResolvedParameter(
       (pi, ctx) => pi.Name == "mummyActor",
       (pi, ctx) => ctx.ResolveNamed<IActorRef>("mummyActorRef")
    )
)
.WithParameter(
  new ResolvedParameter(
       (pi, ctx) => pi.Name == "daddyActor",
       (pi, ctx) => ctx.ResolveNamed<IActorRef>("daddyActorRef")
    )
)
.InstancePerDependency();

我使用参数名称进行检查。但是我认为这个解决方案可能非常危险,特别是如果您重命名参数。

您可以做的另一件事是将这些实例的创建委托(delegate)给具有特定方法的服务/工厂,并且该服务是通过 DI 注入(inject)的。

这是我经过一些重构后得到的:
public class DaddyActor : ReceiveActor
{
    public DaddyActor()
    {
        Receive<DoneEatingMessage>(m =>
        {
            Console.WriteLine("Kid finished eating. So what? ~ Dad");
        });
    }
}
public class MummyActor : ReceiveActor
{
    public MummyActor()
    {
        Receive<DoneEatingMessage>(m =>
        {
            Console.WriteLine("Kid finished eating. Time to clean up! ~Mummy");
        });
    }
}
public class KidActor : ReceiveActor
{
    private IService _service;
    private IActorRef _mummyActor;
    private IActorRef _daddyActor;

    public KidActor(IService service, IParentFactory parentFactory)
    {
        this._service = service;
        this._mummyActor = parentFactory.CreateMother(Context.System);
        this._daddyActor = parentFactory.CreateFather(Context.System);

        Receive<EatMessage>(m =>
        {
            var food = service.GetFood();
            Console.WriteLine("Kid eat this food {0}", food);
            _mummyActor.Tell(new DoneEatingMessage());
            _daddyActor.Tell(new DoneEatingMessage());
        });
    }
}
public class EatMessage { }
public class DoneEatingMessage { }

public interface IService
{
    string GetFood();
}
public class FoodService : IService
{
    public string GetFood()
    {
        return "banana";
    }
}

public interface IParentFactory
{
    IActorRef CreateMother(ActorSystem actorSystem);
    IActorRef CreateFather(ActorSystem actorSystem);
}
public class ParentFactory : IParentFactory
{
    public IActorRef CreateFather(ActorSystem actorSystem)
    {
        return actorSystem.ActorOf(actorSystem.DI().Props<DaddyActor>(), "daddyActor");
    }

    public IActorRef CreateMother(ActorSystem actorSystem)
    {
        return actorSystem.ActorOf(actorSystem.DI().Props<MummyActor>(), "mummyActor");
    }
}

class Program
{
    static ActorSystem _actorSystem;
    static void Main(string[] args)
    {
        var builder = new Autofac.ContainerBuilder();
        builder.RegisterType<FoodService>().As<IService>();
        builder.RegisterType<ParentFactory>().As<IParentFactory>();
        builder.RegisterType<MummyActor>().InstancePerDependency();
        builder.RegisterType<DaddyActor>().InstancePerDependency();
        builder.RegisterType<KidActor>().InstancePerDependency();

        var container = builder.Build();

        _actorSystem = ActorSystem.Create("ActorDISystem");
        var propsResolver = new AutoFacDependencyResolver(container, _actorSystem);

        var kidActorProps = _actorSystem.DI().Props<KidActor>();
        var kidActor = _actorSystem.ActorOf(kidActorProps, "kidActor");

        kidActor.Tell(new EatMessage());

        Console.WriteLine("Holah");
        Console.ReadLine();
        _actorSystem.AwaitTermination();
    }
}

我希望它会帮助你。

关于c# - Akka.net DI - 如何通过 DI 注入(inject)两个 Actor ?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32303894/

10-13 06:04