对依赖注入(
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