依赖注入的加强功能2---扫描Assembly自动注入

对依赖注入( http://www.oschina.net/code/snippet_871522_15682) 的进一步加强.
作为基本功能的注册,使用语法是:registration.register<Interface,Implementation>().
可以到了实际的项目中,要注册的接口和类可能不止一个两个,会成百上千。无论是用C#代码来注册,还是用XML文件来配置,都是开发者的噩梦。

这里,让我们来个思维的反转: 变集中配置为分散声明。
1 为要注册的类,加入RegisterInContainer的声明
2 在系统启动的时候,扫描所有的类,对有RegisterInContainer的类,找到它所有实现的接口,把这些接口和该类绑定注册。

用于装饰要注入类的Attribute.


 1  using  System;
 2  using  System.Linq;
 3  using  Skight.eLiteWeb.Domain.BasicExtensions;
 4 
 5  namespace  Skight.eLiteWeb.Domain.Containers
 6  {
 7      [AttributeUsage(AttributeTargets.Class)]
 8       public   class  RegisterInContainerAttribute : Attribute
 9      {
10           public  RegisterInContainerAttribute(LifeCycle life_cycle) {
11               this .life_cycle  =  life_cycle;
12          }
13 
14           public  LifeCycle life_cycle {  get set ; }
15           public  Type type_to_register_in_container {  get set ; }
16 
17           public   void  register_using(Registration registration) {
18              DiscreteItemResolver resolver  =   new  TypeResolver(type_to_register_in_container);
19               if  (life_cycle  ==  LifeCycle.singleton) resolver  =   new  SingletonResolver(resolver);
20              registration.register(resolver,type_to_register_in_container.all_interface().ToArray());
21          }
22      }
23  }

注入声明Attribute参数,指定是否单件方式生成注册类。


1  namespace  Skight.eLiteWeb.Domain.Containers
2  {
3       public   enum  LifeCycle
4      {
5          single_call,
6          singleton
7      }
8  }

注册声明Attribute的使用示例


 1  // 调用Container.get_an<FrontController>()将会得到FrontControllerImpl的对象
 2 
 3  using  Skight.eLiteWeb.Domain.Containers;
 4 
 5  namespace  Skight.eLiteWeb.Presentation.Web.FrontControllers
 6  {
 7      [RegisterInContainer(LifeCycle.single_call)]
 8       public   class  FrontControllerImpl : FrontControllers.FrontController
 9      {
10           private  CommandResolver command_resolver;
11 
12           public  FrontControllerImpl(CommandResolver commandResolver)
13          {
14              command_resolver  =  commandResolver;
15          }
16 
17           public   void  process(WebRequest request)
18          {
19              command_resolver.get_command_to_process(request).process(request);
20          }
21      }
22  }

Registration添加一个方法:反过来,为一个解析器(实现类)注册多个接口。


1  void  register(DiscreteItemResolver resolver,  params  Type[] contracts);
2 

扫描注册机,在系统启动时调用一次。


 1  using  System.Collections.Generic;
 2  using  System.Reflection;
 3  using  Skight.eLiteWeb.Domain.BasicExtensions;
 4  using  Skight.eLiteWeb.Domain.Containers;
 5 
 6  namespace  Skight.eLiteWeb.Application.Startup
 7  {
 8       public   class  RegistrationScanner:StartupCommand
 9      {
10           private   readonly  Registration registration;
11           private   readonly  IEnumerable < Assembly >  assemblies;
12 
13           public  RegistrationScanner(Registration registration,  params  Assembly[] assemblies)
14          {
15               this .registration  =  registration;
16               this .assemblies  =  assemblies;
17          }
18 
19           public   void  run()
20          {
21              assemblies
22                  .each(assembly  =>
23                        assembly.GetTypes()
24                                .each(type  =>
25                                      type.run_againste_attribute < RegisterInContainerAttribute > (
26                                          attribute  =>
27                                              {
28                                                  attribute.type_to_register_in_container  =  type;
29                                                  attribute.register_using(registration);
30                                              })));
31          }
32      }
33  }

系统启动:创建注册类,然后传入必要的Assembly,调用注册机注册所有加了Attribute的类。


 1  using  System;
 2  using  System.Collections.Generic;
 3  using  System.Reflection;
 4  using  Skight.eLiteWeb.Domain.Containers;
 5  using  Skight.eLiteWeb.Presentation.Web.FrontControllers;
 6 
 7  namespace  Skight.eLiteWeb.Application.Startup
 8  {
 9       public   class  ApplicationStartup
10      {
11           public   void  run()
12          {
13              var registration  =  create_registration();
14               new  RegistrationScanner(registration,
15                                                 Assembly.GetAssembly( typeof  (Container)),
16                                                 Assembly.GetAssembly( typeof  (FrontController)),
17                                                 Assembly.GetAssembly( typeof  (StartupCommand)))
18                                                 .run();
19 
20          }
21 
22           private  Registration create_registration()
23          {
24              IDictionary < Type, DiscreteItemResolver >  item_resolvers  =   new  Dictionary < Type, DiscreteItemResolver > ();
25              Container.initialize_with( new  ResolverImpl(item_resolvers));
26               return   new  RegistrationImpl(item_resolvers);
27          }
28      }
29  }

Global.asax系统入口,把所有的代码串起来。


 1  <% @ Application Language = " C# "   %>
 2  <% @ Import Namespace = " Skight.eLiteWeb.Application.Startup "   %>
 3  < script  RunAt = " server " >
 4 
 5       private   void  Application_Start( object  sender, EventArgs e)
 6      {
 7          new  ApplicationStartup().run();
 8      }
 9 
10  </ script >

原文出自:
http://www.oschina.net/code/snippet_871522_16735

你可能感兴趣的:(依赖注入的加强功能2---扫描Assembly自动注入)