我的问题在于表单,服务等的创建.在ASP.NET MVC中,有一种“激活器”可以做到这一点,但在Windows窗体中并非如此.我必须创建一个像var form = new fclsMain();的新表单,所以一个像…
class fclsMain : System.Windows.Forms.Form { private readonly ISomeRepository<SomeClass> someRepository; fclsMain(ISomeRepository<SomeClass> someRepository) { this.someRepository = someRepository; } }
瀑布有点短.我基本上要做…
var form = new fclsMain(IoC.Resolve< ISomeRepository< SomeClass>);
正如我在至少三个问题中所指出的那样,并不聪明,因为据说这不是IoC的“正确”用法.
那么我如何使用Castle.Windsor和Windows Forms?有没有办法设计Form Activator或其他东西?我真的输了,如果我不能制作一个我可以解决的静态IoC容器,我该怎么办?
public static class CastleContainer { private static IWindsorContainer container; public static IWindsorContainer Instance { get { if (container == null) { container = new WindsorContainer(); } return container; } // exposing a setter alleviates some common component testing problems set { container = value; } } // shortcut to make your life easier :) public static T Resolve<T>() { return Instance.Resolve<T>(); } public static void Dispose() { if (container != null) container.Dispose(); container = null; } }
然后在Main()方法中注册/安装所有组件.您还可以挂钩到应用程序关闭事件以调用Dispose()(尽管这并不重要).
Castle实际上在quick-start guide中使用了Windows Forms应用程序.
编辑:
我上面展示的模式是服务定位器的变体,有些人称之为反模式.它的声誉很差,因为除了其他原因之外,它还引用了Windsor的代码库.理想情况下,您应该只调用一次container.Resolve< ...>()来创建根表单.所有其他服务&形式通过构造函数注入.
实际上,您可能需要再调用一些Resolve,特别是如果您不想在启动时加载应用程序的每个角落.在Web世界中,最佳实践是将容器交给Web框架.在Windows窗体世界中,您需要实现自己的服务定位器,如上所述. (是的,将容器交给ASP.NET MVC框架仍然是服务定位器模式).
我编辑了上面的代码示例,以便静态容器是可注入的;没有资源在静态上下文中被束缚.如果您最终创建自己的服务定位器,您可能还需要创建一个像这样的测试实用程序,以使测试更容易.
public static class TestUtilities { public static IContainer CreateContainer(Action<IContainer> extraConfig = null) { var container = new WindsorContainer(); // 1. Setup common mocks to override prod configuration // 2. Setup specific mocks,when provided if (extraConfig != null) extraConfig(container); // 3. Configure container with production installers CastleContainer.Instance = container; return container; } }
这使得创建一个看起来很像生产版本的新容器的快捷方式,但一些服务被模拟取代.一些示例测试可能如下所示:
[Test] public void SubComponentWorksGreat() { using (var container = TestUtilities.CreateContainer()) { var subComponent = container.Resolve<SubComponent>(); // test it... } } [Test] public void SubComponentWorksGreatWithMocks() { var repoMock = new Mock<IRepository>(); using (var container = TestUtilities.CreateContainer(c => c.Register(Component.For<IRepository>().Instance(repoMock.Object)))) { var subComponent = container.Resolve<SubComponent>(); // test it with all IRepository instances mocked... } }
最后一点.为每个测试创建一个完整的容器可能会变得昂贵.另一种选择是创建完整容器,但仅使用嵌套容器进行实际测试.