.NET中使用Unity和StructureMap来实现依赖注入Dependency Injection

本文用一个非常简单的示例来演示一下如何使用UnityStructureMap在C#中实现Dependency Injection。

我们来做一个非常简单的程序,这个程序会把用户输入的字符串做个逆序,然后输出,同时要求记录一下每次用户的输入和结果,我们支持两种Logger,一种是命令行的,一种是对话框的,用户可以选择使用哪种Logger。

界面如下:

image

这个程序使用MVP来实现的,我们有4个接口如下,分别对应V,P,M和Logger:

    public interface IView
    {
        void DisplayResult(string result);
    }

    public interface IPresenter
    {
        void HandleReverse(string text, IView view);
        void SetLogger(ILogger logger);
    }

    internal interface IModel
    {
        string Reverse(string text);
    }

    public interface ILogger
    {
        void LogMessage(string message);
    }

1. 手工实现依赖注入和singleton。

在App.xaml.cs中我们通过下面的方法来打开UI。可以看到我们用了一堆的new关联起来,创建了一个view。

        protected override void OnStartup(StartupEventArgs e)
        {
            createViewByHand().Show();
        }
        private static Window createViewByHand()
        {
            return new MainWindow(new Presenter(LoggerFactory.CreateLogger(), ModelFactory.CreateModel()));
        }

这里ModelFactory和LoggerFactory是为了保证我们的应用中只有一个Model和Logger的实例。(其实主要是logger,因为model在我们的应用里就一个,但是用户可以选择不同的logger,我们不希望每回用户选择之后都生成一个新的logger)

用户选择下拉框的代码如下:

        private void loggerTypeChanged(object sender, SelectionChangedEventArgs e)
        {
            m_Controller.SetLogger(getLoggerByHand());
        }
        private ILogger getLoggerByHand()
        {
            return LoggerFactory.CreateLogger(loggerType.SelectedItem.ToString());
        }

2. 使用StructureMap实现依赖注入和singleton。

代码如下,我们创建一个Container,配置对应于每个接口,我们使用哪个实例。注意我们在ILogger和IModel中使用了Singleton方法,同时我们配置了2个ILogger的实例,分别设置了一个名字,在用户改变下拉框时,我们从Container中取出相应的实例。

        private static Window createViewByStructureMap()
        {
            StructureMapContainer = new StructureMap.Container(x =>
            {
                x.For<IPresenter>().Use<Presenter>();
                x.For<IView>().Use<MainWindow>();
                x.For<IModel>().Singleton().Use<ReverseModel>();
                x.AddType(typeof(ILogger), typeof(MessageBoxLogger), LoggerFactory.MessageboxLoggerName);
                x.AddType(typeof(ILogger), typeof(ConsoleLogger), LoggerFactory.ConsoleLoggerName);
                x.For<ILogger>().Singleton().UseSpecial(y => y.TheInstanceNamed(LoggerFactory.ConsoleLoggerName));
            });
            StructureMapContainer.AssertConfigurationIsValid();

            return StructureMapContainer.GetInstance<MainWindow>();
        }

        private ILogger getLoggerByStructureMap()
        {
            return App.StructureMapContainer.GetInstance<ILogger>(loggerType.SelectedItem.ToString());
        }

3. 使用Unity实现依赖注入和singleton。

代码非常类似,只是用ContainerControlledLifetimeManager来实现singleton。

        private Window createViewByUnity()
        {
            UnityContainer = new UnityContainer();
            UnityContainer.RegisterType<IPresenter, Presenter>();
            UnityContainer.RegisterType<IView, MainWindow>();
            UnityContainer.RegisterType<IModel, ReverseModel>(new ContainerControlledLifetimeManager());
            UnityContainer.RegisterType<ILogger, ConsoleLogger>(LoggerFactory.ConsoleLoggerName,
                                                                new ContainerControlledLifetimeManager());
            UnityContainer.RegisterType<ILogger, MessageBoxLogger>(LoggerFactory.MessageboxLoggerName,
                                                                   new ContainerControlledLifetimeManager());
            return UnityContainer.RegisterInstance(typeof(ILogger), UnityContainer.Resolve<ILogger>(LoggerFactory.ConsoleLoggerName)).Resolve<MainWindow>();
        }

        private ILogger getLoggerByUnity()
        {
            return App.UnityContainer.Resolve<ILogger>(loggerType.SelectedItem.ToString());
        }

另外StructureMap和Unity都支持Attribute来制定应该往哪个属性上Inject。StructureMap是[SetterProperty],Unity是 [Dependency]。

具体的实现就不详细列出来,可以在github上找到源码。

原文地址:https://www.cnblogs.com/fresky/p/2828710.html