背景
我使用带有MVP模式的Winforms来创建应用程序。我使用SimpleInjector作为我的IoC容器。我的演讲者继承自:
public interface IPresenter<TView>
{
TView View { get; set; }
}
internal class HomePresenter : IPresenter<IHomeView>
{
public IHomeView View { get; set; }
...
}
为了创建我的演示者,我决定使用以下方法的演示者工厂:
public static IPresenter<TView> CreateForView<TView>(TView view)
{
var presenter = _container.GetInstance<IPresenter<TView>>();
presenter.View = view;
return presenter;
}
然后在每个视图中,视图通过调用演示者工厂创建自己的演示者:
_homeMainPresenter = (HomePresenter) presenterFactory.CreateForView<IHomeView>(this);
_homeMainPresenter.View = this;
在我的Program.cs文件中,我有:
static void Main()
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
System.Windows.Forms.Application.Run((HomeView)container.GetInstance<IHomeView>());
}
private static void Bootstrap()
{
// Create the container
container = new Container();
// Register types
container.Register<IHomeView, HomeView>(Lifestyle.Singleton);
container.Register<IPresenter<IHomeView>, HomePresenter>();
...
// Verify the container
container.Verify();
}
问题
当从HomeView视图调用演示者工厂时,输入工厂的类型是HomeView类型,而不是IHomeView。因此,应用程序抛出异常,因为容器没有HomeView注册(仅IHomeView)。我的演示者都有他们存储的视图参考的接口,因为我觉得这对测试更好。我该如何避免这种情况?
答案 0 :(得分:2)
对表单实现接口到实现的绑定没有用,因为它们是表示技术的根类型。大多数演示技术无论如何都无法处理自定义抽象,这就是您将IHomeView
强制转换回HomeView
以允许将其传递给Application.Run
方法的原因
您可以执行以下操作,而不是从视图中解析演示者:
public interface IHomeView { }
public interface IPresenter<TView> {
TView View { get; set; }
}
public class HomeView : Form, IHomeView
{
private readonly IPresenter<IHomeView> presenter;
public HomeView(IPresenter<IHomeView> presenter) {
this.presenter = presenter;
InitializeComponent();
}
}
这里Form注入一个IPresenter<IHomeView>
并存储传入的依赖项。不再需要工厂,可以从代码中删除。
在你的程序主页中:
static void Main()
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
System.Windows.Forms.Application.Run(GetForm<HomeView, IHomeView>(container));
}
private static void Bootstrap()
{
// Create the container
container = new Container();
// Register types
// NOTE: We register HomeView as concrete type; not by its interface.
container.Register<HomeView>(Lifestyle.Singleton);
// Here we batch-register all presenters with one line of code and
// since the forms depend on them, they need to be singletons as well.
container.Register(typeof(IPresenter<>), AppDomain.CurrentDomain.GetAssemblies(),
Lifestyle.Singleton);
...
// Verify the container
container.Verify();
}
private static TForm GetForm<TForm, TView>() where TForm : Form, TView
{
var form = container.GetInstance<TForm>();
container.GetInstance<IPresenter<TView>>().View = form;
return form;
}
现在,工厂类已替换为组合根的GetForm
方法;表单无法访问它。通用类型允许我们解析适当的演示者,同时保持代码类型安全。