在Ninject(Compact Framework)中解决周期性依赖

时间:2010-04-01 06:48:30

标签: c# .net compact-framework ninject

我正在尝试在我的MVP应用程序中使用Ninject进行依赖注入。但是,我有一个问题,因为我有两种相互依赖的类型,因此创建了一个循环依赖。起初,我理解这是一个问题,因为我有两种类型在他们的构造函数中相互需要。因此,我将其中一个依赖项移动到属性注入,但我仍然收到错误消息。我做错了什么?

这是演示者:

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 :(得分:0)

通过创建“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 );
    }
}

主持人保持不变。这样,我手动“解决”循环依赖。当然,仍然欢迎更好的建议。