Циклическая зависимость с нинъектом - PullRequest
11 голосов
/ 18 августа 2010

Я пытаюсь найти правильный способ связать что-то подобное с помощью ninject.

interface IMainService
{
    void DoStuff();
}

interface IOtherService
{
    void DoSomeMagic();
}

abstract class BaseClass
{
    //many stuff here
}

class MainClass : BaseClass, IMainService
{
    public MainClass(IOtherService s)
    {
    }

    public void DoStuff()
    {
        throw new NotImplementedException();
    }

    //do many other things
}

class OtherClass : IOtherService
{
    public OtherClass(IMainService s)
    {
    }

    public void DoSomeMagic()
    {
        throw new NotImplementedException();
    }
}

class BaseModule : NinjectModule
{
    public override void Load()
    {
        Bind<MainClass>().To<MainClass>();
        Bind<IMainService>().To<MainClass>();
        Bind<IOtherService>().To<OtherClass>();
    }
}

static class Program
{
    static void Main()
    {
        var kernel = new StandardKernel(new BaseModule());
        var main = kernel.Get<MainClass>();
    }
}

Это дает мне исключение:

Error activating IOtherService using binding from IOtherService to OtherClass
A cyclical dependency was detected between the constructors of two services.

Activation path:
  4) Injection of dependency IOtherService into parameter s of constructor of type MainClass
  3) Injection of dependency IMainService into parameter s of constructor of type OtherClass
  2) Injection of dependency IOtherService into parameter s of constructor of type MainClass
  1) Request for MainClass

Suggestions:
  1) Ensure that you have not declared a dependency for IOtherService on any implementations of the service.
  2) Consider combining the services into a single one to remove the cycle.
  3) Use property injection instead of constructor injection, and implement IInitializable if you need initialization logic to be run after property values have been injected.

Я не знаю, какнаписать BaseModule.Мне нужен только один экземпляр MainClass и один экземпляр OtherClass (например, синглтоны).

Я пробовал такие вещи:

Bind<MainClass>().To<MainClass>().InSingletonScope();
Bind<IMainService>().To<MainClass>().InRequestScope();
Bind<IOtherService>().To<OtherClass>().InSingletonScope();

Но с той же ошибкой.

ИКак написать привязку для использования только одного экземпляра для интерфейсов MainClass и IMainService?

Спасибо за ответы.

Ответы [ 2 ]

16 голосов
/ 18 августа 2010

Как говорится в сообщении об ошибке, у вас есть циклическая зависимость между MainClass и OtherClass, поскольку вы не можете создать одно без экземпляра другого.В идеале вам следует реструктурировать иерархию классов, чтобы устранить это требование.

Если вы не можете, решение состоит в том, чтобы использовать внедрение свойства для одного (или обоих) классов, например,

public interface IMainService
{
    void DoStuff();
    IOtherService OtherService { set; }
}

public class MainClass
{
    public IOtherService OtherService { get; set; }
    public void DoStuff() { ... }
}

public class OtherService
{
    public OtherService(IMainService main)
    {
        main.OtherService = this;
    }
}
5 голосов
/ 22 февраля 2017

Я думаю, что вы не должны использовать свойства или методы установки для этого, вам лучше использовать Lazyness. Концепция ленивости решает проблему. Проблема в том, что если у вас круговая зависимость между объектами, становится неясно, что нужно создать первым. Ленивость разрешается следующим образом: если объект действительно используется (в общем случае, когда вызывается открытый метод, он должен существовать). Пожалуйста, избегайте свойств или сеттеров, если можете. Они делают ваш объект изменчивым (плохо для безопасности потоков и не нужны, когда зависимость должна быть введена только один раз).

Ваши конструкторы должны выглядеть так:

public OtherService(Lazy<IMainService> main)
{
    this.main = main;
}

public MainClass(Lazy<IOtherService> s)
{
    this.s = s;
}

Вы можете описать эти ленивые зависимости в модуле Ninject, используя метод Load, вызвав "ToMethod (" лямбда-метод, который создает метод Lazy на основе метода get ").

Здесь представлен ясный пример того, как ленивость может решить круговые зависимости с помощью Ninject. Также описывается вспомогательный метод (BindLazy) для решения вашей проблемы. https://www.codeproject.com/Tips/1171940/How-Ninject-Can-Help-in-Resolving-Circular-Depende

...