Winforms IoC 容器 - 如何使用演示工厂处理具体类型
Winforms IoC Container - How to handle concrete types with a presenter factory
背景
我正在使用具有 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 视图调用 Presenter 工厂时,输入工厂的类型是 HomeView 类型,而不是 IHomeView。所以,应用程序抛出异常,因为容器没有 HomeView 注册(只有 IHomeView)。我的演示者都有他们存储的视图引用的接口,因为我觉得这对于测试来说会更好。我该如何避免这种情况?
为表单设置接口到实现的绑定没有用,因为它们是表示技术的根类型。大多数表示技术无论如何都无法处理自定义抽象,这就是您将 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();
}
}
这里的表单被注入 IPresenter<IHomeView>
并存储传入的依赖项。工厂不再需要,可以从您的代码中删除。
并且在您的程序 main 中:
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;
}
工厂 class 现在被作为组合根的一部分的 GetForm
方法替换;表单无权访问它。通用类型允许我们解析正确的呈现器,同时保持代码类型安全。
背景
我正在使用具有 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 视图调用 Presenter 工厂时,输入工厂的类型是 HomeView 类型,而不是 IHomeView。所以,应用程序抛出异常,因为容器没有 HomeView 注册(只有 IHomeView)。我的演示者都有他们存储的视图引用的接口,因为我觉得这对于测试来说会更好。我该如何避免这种情况?
为表单设置接口到实现的绑定没有用,因为它们是表示技术的根类型。大多数表示技术无论如何都无法处理自定义抽象,这就是您将 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();
}
}
这里的表单被注入 IPresenter<IHomeView>
并存储传入的依赖项。工厂不再需要,可以从您的代码中删除。
并且在您的程序 main 中:
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;
}
工厂 class 现在被作为组合根的一部分的 GetForm
方法替换;表单无权访问它。通用类型允许我们解析正确的呈现器,同时保持代码类型安全。