Решение циклической зависимости в Ninject (Compact Framework) - PullRequest
2 голосов
/ 01 апреля 2010

Я пытаюсь использовать Ninject для внедрения зависимостей в моем приложении MVP. Однако у меня есть проблема, потому что у меня есть два типа, которые зависят друг от друга, создавая таким образом циклическую зависимость. Сначала я понимаю, что это была проблема, потому что у меня оба типа требовали друг друга в своих конструкторах. Поэтому вместо этого я перенес одну из зависимостей в инъекцию свойства, но все равно получаю сообщение об ошибке. Что я делаю не так?

Это ведущий:

public class LoginPresenter : Presenter<ILoginView>, ILoginPresenter
{
    private ISettings _settings;
    private IViewProvider _viewProvider;
    private IDataProvider _dataProvider;

    public LoginPresenter(
        ILoginView view,
        ISettings settings,
        IViewProvider viewProvider,
        IDataProvider dataProvider )
        : base( view )
    {
        _settings = settings;
        _viewProvider = viewProvider;
        _dataProvider = dataProvider;
    }
}

и это вид:

public partial class LoginForm : Form, ILoginView
{
    [Inject]
    public ILoginPresenter Presenter { private get; set; }

    public LoginForm()
    {
        InitializeComponent();
    }
}

А вот код, который вызывает исключение:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [MTAThread]
    static void Main()
    {
        // Show the login form
        Views.LoginForm loginForm = Kernel.Get<Views.Interfaces.ILoginView>() as Views.LoginForm;
        Application.Run( loginForm );
    }
}

Исключение происходит в строке с вызовом Kernel.Get<>(). Вот оно:

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

Activation path:
  4) Injection of dependency ILoginPresenter into property Presenter of type LoginForm
  3) Injection of dependency ILoginView into parameter view of constructor of type LoginPresenter
  2) Injection of dependency ILoginPresenter into property Presenter of type LoginForm
  1) Request for ILoginView

Suggestions:
  1) Ensure that you have not declared a dependency for ILoginPresenter 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.

Почему Ninject не понимает, что, поскольку один из них является инжектором конструктора, а другой - внедрением свойств, это может работать просто отлично? Я даже читал где-то в поисках решения этой проблемы, что Ninject якобы понимает это правильно, пока циклическая зависимость отсутствует в конструкторах. Видимо, нет. Любая помощь в решении этой проблемы будет принята с благодарностью.

Согласно Википедии, для View является обычным создание экземпляра своего конкретного презентатора вручную, но я не могу этого сделать в моем случае, потому что, как вы видите, у презентатора есть и другие зависимости, которые также необходимо разрешить. *

1 Ответ

0 голосов
/ 01 апреля 2010

Я решил проблему, создав «PresenterProvider»:

public interface IPresenterProvider
{
    P Get<P, V>( V view )
        where V : IView
        where P : IPresenter<V>;
}

public class PresenterProvider : IPresenterProvider
{
    private IKernel _kernel;

    public PresenterProvider( IKernel kernel )
    {
        _kernel = kernel;
    }

    #region IPresenterProvider Members

    public P Get<P, V>( V view )
        where P : IPresenter<V>
        where V : IView
    {
        return _kernel.Get<P>( new ConstructorArgument( "view", view ) );
    }

    #endregion
}

Затем в представлении я делаю это:

public partial class LoginForm : Form, ILoginView
{
    private ILoginPresenter _presenter;

    public LoginForm( IPresenterProvider presenterProvider )
    {
        InitializeComponent();
        _presenter = presenterProvider.Get<ILoginPresenter, ILoginView>( this );
    }
}

Ведущий остается прежним. Таким образом, я "решаю" циклическую зависимость вручную. Конечно, лучшие предложения все еще приветствуются.

...