Contents
  1. 1. 1. 手工实现依赖注入和singleton。
  2. 2. 2. 使用StructureMap实现依赖注入和singleton。
  3. 3. 3. 使用Unity实现依赖注入和singleton。

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

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

界面如下:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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。

1
2
3
4
5
6
7
8
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)

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

1
2
3
4
5
6
7
8
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中取出相应的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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上找到源码。










Contents
  1. 1. 1. 手工实现依赖注入和singleton。
  2. 2. 2. 使用StructureMap实现依赖注入和singleton。
  3. 3. 3. 使用Unity实现依赖注入和singleton。