Container注入框架的进入点
1 namespace Skight.LightWeb.Domain
2 {
3 public class Container
4 {
5 private static Resolver underlying_resolver;
6 public static Resolver Current
7 {
8 get { return underlying_resolver; }
9 }
10 public static T get_a<T>()
11 {
12 return underlying_resolver.get_a<T>();
13 }
14
15 public static void initialize_with(Resolver resolver)
16 {
17 underlying_resolver = resolver;
18 }
19 }
20 }
Container的实现核心,依赖解析器的接口定义。(接口名称,我不加I,故意的)
1 using System;
2
3 namespace Skight.LightWeb.Domain
4 {
5 public interface Resolver
6 {
7 Dependency get_a<Dependency>();
8 object get_a(Type type);
9 }
10 }
依赖解析器的测试 (使用Machine Specification)
1 using System;
2 using System.Collections.Generic;
3 using Machine.Specifications;
4 using Rhino.Mocks;
5
6 namespace Skight.LightWeb.Domain.Specs
7 {
8 public class When_bind_a_class_to_a_intefercate
9 {
10 private Establish context =
11 () =>
12 {
13 var item_resolver = MockRepository.GenerateMock<DiscreteItemResolver>();
14 var dictioary = new Dictionary<Type, DiscreteItemResolver>();
15 dictioary.Add(typeof (MockInterface), item_resolver);
16 subject = new ResolverImpl(dictioary);
17 item_resolver.Stub(x => x.resolve()).Return(new MockImplementaion());
18 };
19
20 private It should_resolve_the_interface_to_the_class =
21 () => subject.get_a<MockInterface>().ShouldBeOfType<MockImplementaion>();
22
23 private static ResolverImpl subject;
24 private interface MockInterface { }
25 private class MockImplementaion : MockInterface { }
26
27 }
28 }
解构器的实现
1 using System;
2 using System.Collections.Generic;
3
4 namespace Skight.LightWeb.Domain
5 {
6 public class ResolverImpl:Resolver
7 {
8 private readonly IDictionary<Type, DiscreteItemResolver> item_resolvers;
9
10 public ResolverImpl(IDictionary<Type, DiscreteItemResolver> itemResolvers)
11 {
12 item_resolvers = itemResolvers;
13 }
14
15 public Dependency get_a<Dependency>()
16 {
17 return (Dependency) item_resolvers[typeof (Dependency)].resolve();
18 }
19
20 public object get_a(Type type)
21 {
22 return item_resolvers[type].resolve();
23 }
24 }
25 }
注册器的接口定义 (是的,先要注册才能解析,可是业务视图却是反的)
1 namespace Skight.LightWeb.Domain
2 {
3 public interface Registration
4 {
5 void register<Contract, Implementaion>() where Implementaion : Contract;
6 }
7 }
注册器的的测试
1 using System;
2 using System.Collections.Generic;
3 using Machine.Specifications;
4
5 namespace Skight.LightWeb.Domain.Specs
6 {
7 public class When_use_Registration_to_register_an_infterface_to_a_class
8 {
9 private Establish context =
10 () =>
11 {
12 resolver_dictionary = new Dictionary<Type, DiscreteItemResolver>();
13 subject = new RegistrationImpl(resolver_dictionary);
14
15 };
16
17 private Because of =
18 () => subject.register<MockInterface, MockImplementation>();
19
20 private It the_key_value_pair_should_be_added_to_resovler_dictionary =
21 () => resolver_dictionary[typeof (MockInterface)].resolve().ShouldBeOfType<MockImplementation>();
22
23 private static RegistrationImpl subject;
24 private static Dictionary<Type, DiscreteItemResolver> resolver_dictionary;
25
26 private interface MockInterface{}
27 private class MockImplementation:MockInterface {}
28 }
29 }
注册器的的实现
1 using System;
2 using System.Collections.Generic;
3
4 namespace Skight.LightWeb.Domain
5 {
6 public class RegistrationImpl:Registration
7 {
8 private IDictionary<Type, DiscreteItemResolver> item_resolvers;
9 public RegistrationImpl(IDictionary<Type, DiscreteItemResolver> item_resolvers)
10 {
11 this.item_resolvers = item_resolvers;
12 }
13
14 public void register<Contract, Implementation>() where Implementation : Contract
15 {
16
17 item_resolvers.Add(typeof(Contract), new TypeResolver(typeof(Implementation)));
18 }
19 }
20
21 }
具体解构器接口定义 (命名:离散解构器,可以看作是对象工厂的一种形式)
1 namespace Skight.LightWeb.Domain
2 {
3 public interface DiscreteItemResolver
4 {
5 object resolve();
6 }
7 }
离散解构器的测试
1 using System;
2 using Machine.Specifications;
3 using Rhino.Mocks;
4
5 namespace Skight.LightWeb.Domain.Specs
6 {
7 public class TypeResolverSpecs
8 {
9 protected static TypeResolver subject;
10 }
11
12 public class given_a_simple_type_which_has_a_parameterless_constructor
13 : TypeResolverSpecs
14 {
15 private Establish context =
16 () => subject = new TypeResolver(typeof (SimpleType));
17
18 private It should_create_object_from_class =
19 () => subject.resolve().ShouldBeOfType<SimpleType>();
20
21 protected class SimpleType{}
22 }
23
24 public class given_a_complex_type_whose_constructor_need_other_types
25 : TypeResolverSpecs {
26 private Establish context =
27 () =>
28 {
29 var resolver = MockRepository.GenerateMock<Resolver>();
30 Container.initialize_with(resolver);
31 resolver.Stub(x => x.get_a(Arg<Type>.Is.Equal(typeof (SimpleType))))
32 .Return(new SimpleType());
33
34 subject = new TypeResolver(typeof (ComplexType));
35 };
36
37 private It should_create_object_from_class =
38 () => subject.resolve().ShouldBeOfType<ComplexType>();
39
40 protected class SimpleType{}
41 protected class ComplexType
42 {
43 private SimpleType simple;
44
45 public ComplexType(SimpleType simple)
46 {
47 this.simple = simple;
48 }
49 }
50 }
51 }
离散解构器的实现 (有递归,如果该类构造器有接口参数的,需要用Container解构)
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Reflection;
5
6 namespace Skight.LightWeb.Domain
7 {
8 public class TypeResolver:DiscreteItemResolver
9 {
10 private readonly Type type_to_create;
11
12 public TypeResolver(Type type_to_create)
13 {
14 this.type_to_create = type_to_create;
15 }
16
17 public object resolve()
18 {
19 ParameterInfo[] param_types = get_constructor_parameters();
20 IEnumerable<object> parameters = get_parameters(param_types);
21 return Activator.CreateInstance(type_to_create, parameters.ToArray());
22 }
23
24 private IEnumerable<object> get_parameters(ParameterInfo[] param_types)
25 {
26 return param_types.Select(x => Container.Current.get_a(x.ParameterType));
27 }
28
29 private ParameterInfo[] get_constructor_parameters()
30 {
31 var constructor= type_to_create.GetConstructors()
32 .OrderByDescending(x => x.GetParameters().Count())
33 .First();
34 return constructor.GetParameters();
35 }
36 }
37 }
集成测试,完整的用例。
1 using System;
2 using System.Collections.Generic;
3 using Machine.Specifications;
4
5 namespace Skight.LightWeb.Domain.Specs
6 {
7 public class DependencyIntegrationSpecs
8 {
9 private Establish context =
10 () =>
11 {
12 IDictionary<Type, DiscreteItemResolver> item_resolvers = new Dictionary<Type, DiscreteItemResolver>();
13 registration = new RegistrationImpl(item_resolvers);
14 Container.initialize_with(new ResolverImpl(item_resolvers));
15
16 };
17
18 protected static Registration registration;
19 }
20
21 public class when_registry_a_simple_class_RepositoryImpl_without_further_dependency:DependencyIntegrationSpecs
22 {
23 private Establish context =
24 () => registration.register<Repository, RepositoryImpl>();
25 private Because of =
26 () => result = Container.get_a<Repository>();
27
28 private It should_get_a_object_which_is_not_null =
29 () => result.ShouldNotBeNull();
30
31 private It should_get_RepositoryImpl_class =
32 () => result.ShouldBeOfType<RepositoryImpl>();
33
34 private static Repository result;
35 }
36
37 public class when_registry_a_class_ServiceImpl_which_depend_on_another_interface_Repository : DependencyIntegrationSpecs {
38 private Establish context =
39 () => {
40 registration.register<Repository, RepositoryImpl>();
41 registration.register<Service,ServiceImpl>();
42 };
43 private Because of =
44 () => result = Container.get_a<Service>();
45
46 private It inject_repository_should_not_be_null =
47 () => result.ShouldNotBeNull();
48
49 private It should_inject_service =
50 () => result.ShouldBeOfType<ServiceImpl>();
51
52 private It should_inject_repository_into_service =
53 () => result.Repository.ShouldBeOfType<RepositoryImpl>();
54
55
56 private static Service result;
57 }
58 public interface Repository { }
59 public class RepositoryImpl : Repository { }
60 public interface Service{Repository Repository { get; } }
61 public class ServiceImpl : Service
62 {
63 private Repository repository;
64
65 public ServiceImpl(Repository repository)
66 {
67 this.repository = repository;
68 }
69
70 public Repository Repository
71 {
72 get { return repository; }
73 }
74 }
75 }
Bootstrapper系鞋带代码,把所有的碎片组合起来,作为Web,在Gloable.asax中调用
1 using System;
2 using System.Collections.Generic;
3 using Skight.LightWeb.Domain;
4 using Skight.LightWeb.Presentation.Web.FrontController;
5
6
7 namespace Skight.LightWeb.Application.Startup
8 {
9 public class ApplicationStartup
10 {
11 public void run()
12 {
13 IDictionary<Type, DiscreteItemResolver> item_resolvers = new Dictionary<Type, DiscreteItemResolver>();
14 Container.initialize_with(new ResolverImpl(item_resolvers));
15 var registration = new RegistrationImpl(item_resolvers);
16 registration.register<Repository,RepositoryImpl>();
17 registration.register<FrontController,FrontControllerImpl>();
18 registration.register<CommandResolver,CommandResolverImpl>();
19
20 }
21
22 /// <summary>
23 /// Test purpose class an interface
24 /// </summary>
25 public interface Repository { }
26 public class RepositoryImpl : Repository { }
27 }
28 }
原文出自:
http://www.oschina.net/code/snippet_871522_15682