2


2

Ninjectの循環依存関係の解決(コンパクトフレームワーク)

MVPアプリケーションで依存性注入にNinjectを使用しようとしています。 ただし、相互に依存する2つのタイプがあるため、循環依存関係が作成されるため、問題があります。 最初は、両方のタイプがコンストラクターで互いに必要とするため、それが問題であることを理解しています。 そのため、代わりに依存関係の1つをプロパティインジェクションに移動しましたが、それでもエラーメッセージが表示されます。 何がおかしいのですか?

これがプレゼンターです。

public class LoginPresenter : Presenter, 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
{
    ///
    /// The main entry point for the application.
    ///
    [MTAThread]
    static void Main()
    {
        // Show the login form
        Views.LoginForm loginForm = Kernel.Get() 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.

1つはコンストラクター注入で、もう1つはプロパティー注入であるため、Ninjectが理解できないのはなぜですか? 巡回依存関係が両方ともコンストラクターにない限り、Ninjectがこの問題を正しく解決するというこの問題の解決策を探しているところも読んでいます。 しかし、明らかにそうではありません。 これを解決するための助けをいただければ幸いです。

ウィキペディアによると、Viewがその具体的なプレゼンターを手動でインスタンス化することは一般的ですが、私の場合、それを行うことはできません。

1 Answer


0


「PresenterProvider」を作成して問題を「回避」しました:

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

public class PresenterProvider : IPresenterProvider
{
    private IKernel _kernel;

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

    #region IPresenterProvider Members

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

    #endregion
}

次に、ビューでこれを行います:

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

    public LoginForm( IPresenterProvider presenterProvider )
    {
        InitializeComponent();
        _presenter = presenterProvider.Get( this );
    }
}

プレゼンターは変わりません。 このようにして、周期的な依存関係を手動で「解決」しています。 もちろん、より良い提案を歓迎します。