• .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上找到源码。

  • 相关阅读:
    CUDA 函数前缀与存储器前缀讨论
    VC++控制台程序中使用定时器
    C++中的RTTI
    C/C++ 时间转换与表示
    [转]winsock和winsock2冲突
    自然归并排序 c++ (原创)
    关于CC++运行时库的多线程版本的工作记录
    关于sizeof(原)
    结构体最后的长度为0或1数组的作用(转载)
    CUDA中常见的错误:the launch timed out and was treminated.
  • 原文地址:https://www.cnblogs.com/fresky/p/2828710.html
Copyright © 2020-2023  润新知