Skip to content

Commit 21bc2fa

Browse files
committed
L10: Z2
1 parent e0884ac commit 21bc2fa

13 files changed

+186
-27
lines changed

OopL9/SimpleIoc.Tests/L10Tests.cs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using SimpleIoc.Exceptions;
34
using SimpleIoc.Tests.Types;
45

56
namespace SimpleIoc.Tests
@@ -23,10 +24,63 @@ public void DependencyContructor()
2324
{
2425
var c = new SimpleContainer();
2526
c.RegisterType<ITypeToResolveWithConstructorParams, ConcreteTypeWithDependencyConstructorAttr>();
27+
c.RegisterType<ITypeToResolve, ConcreteType>();
2628
var foo = c.Resolve<ITypeToResolveWithConstructorParams>();
2729

2830
Assert.IsNotNull(foo.Arg1);
2931
Assert.IsNull(foo.Arg2);
3032
}
33+
34+
[TestMethod]
35+
[ExpectedException(typeof (CyclicDependencyException))]
36+
public void NoResolvableConstructor()
37+
{
38+
var c = new SimpleContainer();
39+
40+
// wyjątek, string nie ma konstruktora bezparametrowego i nie da się rozwikłać żadnego z konstruktorów
41+
c.Resolve<ConcreteWithStringParam>();
42+
}
43+
44+
[TestMethod]
45+
public void ResolvableWithInstance()
46+
{
47+
var c = new SimpleContainer();
48+
49+
c.RegisterInstance("ala ma kota"); // rejestruje instancję string
50+
// jest ok, zarejestrowano instancję string więc rozwikłanie konstruktora X jest możliwe
51+
c.Resolve<ConcreteWithStringParam>();
52+
}
53+
54+
[TestMethod]
55+
public void ResolvableSecondConstructor()
56+
{
57+
var c = new SimpleContainer();
58+
59+
c.RegisterType<ITypeToResolve, ConcreteType>();
60+
var instance = c.Resolve<ConcreteWithResolvableSecondConstructor>();
61+
Assert.IsNotNull(instance.Arg1);
62+
}
63+
64+
[TestMethod]
65+
[ExpectedException(typeof(CyclicDependencyException))]
66+
[Timeout(1000)]
67+
public void CyclicDependencySimple()
68+
{
69+
var c = new SimpleContainer();
70+
71+
c.RegisterType<ITypeToResolve, ConcreteWithSimpleCyclicDependency>();
72+
c.Resolve<ITypeToResolve>();
73+
}
74+
75+
[TestMethod]
76+
[ExpectedException(typeof(CyclicDependencyException))]
77+
//[Timeout(1000)]
78+
public void CyclicDependencyNested()
79+
{
80+
var c = new SimpleContainer();
81+
82+
c.RegisterType<ITypeToResolve, ConcreteWithCyclicDependency>();
83+
c.Resolve<ITypeToResolve>();
84+
}
3185
}
32-
}
86+
}

OopL9/SimpleIoc.Tests/L9Tests.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ public void ResolveObjectWithInterface()
1919
Assert.IsInstanceOfType(instance, typeof(ConcreteType));
2020
}
2121

22+
[TestMethod]
23+
public void ResolveConcreteTypeDefault()
24+
{
25+
var container = new SimpleContainer();
26+
var instance = container.Resolve<ConcreteType>();
27+
28+
Assert.IsNotNull(instance);
29+
Assert.AreNotSame(container.Resolve<ConcreteType>(), instance);
30+
}
31+
2232
[TestMethod]
2333
public void ResolveConcreteTypeSingleton()
2434
{
@@ -28,7 +38,7 @@ public void ResolveConcreteTypeSingleton()
2838
var instance = container.Resolve<ConcreteType>();
2939

3040
Assert.AreSame(container.Resolve<ConcreteType>(), instance);
31-
}
41+
}
3242

3343
[TestMethod]
3444
public void ResolveConcreteTypeTransient()

OopL9/SimpleIoc.Tests/SimpleIoc.Tests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,13 @@
5050
</Otherwise>
5151
</Choose>
5252
<ItemGroup>
53+
<Compile Include="Types\ConcreteWithCyclicDependency.cs" />
54+
<Compile Include="Types\ConcreteWithSimpleCyclicDependency.cs" />
55+
<Compile Include="Types\ConcreteWithResolvableSecondConstructor.cs" />
5356
<Compile Include="Types\ConcreteType.cs" />
5457
<Compile Include="Types\ConcreteTypeWithConstructorParams.cs" />
5558
<Compile Include="Types\ConcreteTypeWithDependencyConstructorAttr.cs" />
59+
<Compile Include="Types\ConcreteWithStringParam.cs" />
5660
<Compile Include="Types\ITypeToResolve.cs" />
5761
<Compile Include="Types\ITypeToResolveWithConstructorParams.cs" />
5862
<Compile Include="L9Tests.cs" />
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace SimpleIoc.Tests.Types
2+
{
3+
public class ConcreteWithCyclicDependency : ITypeToResolve
4+
{
5+
public ConcreteWithCyclicDependency(ConcreteWithSimpleCyclicDependency param)
6+
{
7+
}
8+
}
9+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace SimpleIoc.Tests.Types
2+
{
3+
public class ConcreteWithResolvableSecondConstructor : ITypeToResolveWithConstructorParams
4+
{
5+
public ITypeToResolve Arg1 { get; set; }
6+
public ITypeToResolve Arg2 { get; set; }
7+
8+
public ConcreteWithResolvableSecondConstructor(ITypeToResolve arg1, string param)
9+
{
10+
}
11+
12+
public ConcreteWithResolvableSecondConstructor(ITypeToResolve arg1)
13+
{
14+
Arg1 = arg1;
15+
}
16+
}
17+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace SimpleIoc.Tests.Types
2+
{
3+
public class ConcreteWithSimpleCyclicDependency : ITypeToResolve
4+
{
5+
public ConcreteWithSimpleCyclicDependency(ITypeToResolve param)
6+
{
7+
}
8+
}
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace SimpleIoc.Tests.Types
2+
{
3+
public class ConcreteWithStringParam : ITypeToResolveWithConstructorParams
4+
{
5+
public ITypeToResolve Arg1 { get; set; }
6+
public ITypeToResolve Arg2 { get; set; }
7+
8+
public ConcreteWithStringParam(string param)
9+
{
10+
11+
}
12+
}
13+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using System;
2+
3+
namespace SimpleIoc.Exceptions
4+
{
5+
public class CyclicDependencyException : Exception
6+
{
7+
}
8+
}

OopL9/SimpleIoc/IContainer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public interface IContainer
88
void RegisterType<TFrom, TTo>(bool singleton) where TTo : TFrom;
99
T Resolve<T>();
1010

11-
void RegisterInstance<T>(T Instance);
11+
void RegisterInstance<T>(T instance);
1212

1313
#endregion
1414
}

OopL9/SimpleIoc/SimpleContainer.cs

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,54 +16,88 @@ public class SimpleContainer : IContainer
1616
#endregion
1717
#region Private methods
1818

19-
private object GetInstance(RegisteredObject registeredObject)
19+
private object GetInstance(RegisteredObject registeredObject, HashSet<Type> resolvingTypes = null)
2020
{
2121
if (registeredObject.Instance == null ||
2222
registeredObject.LifeCycle == LifeCycle.Transient)
2323
{
24-
var constructorInfo = ResolveConstructor(registeredObject);
25-
var parameters = ResolveConstructorParameters(constructorInfo);
26-
registeredObject.CreateInstance(parameters.ToArray());
24+
foreach (var constructorInfo in ResolveConstructors(registeredObject))
25+
{
26+
try
27+
{
28+
if (resolvingTypes == null)
29+
{
30+
resolvingTypes = new HashSet<Type> {registeredObject.TypeToResolve};
31+
}
32+
else
33+
{
34+
resolvingTypes.Add(registeredObject.TypeToResolve);
35+
}
36+
37+
var parameters = constructorInfo.GetParameters().Select(pi => pi.ParameterType).ToArray();
38+
if (parameters.Any(resolvingTypes.Contains))
39+
{
40+
throw new CyclicDependencyException();
41+
}
42+
43+
registeredObject.CreateInstance(parameters.Select(pi => ResolveObject(pi, resolvingTypes)).ToArray());
44+
}
45+
catch (MissingMethodException)
46+
{
47+
continue;
48+
}
49+
break;
50+
}
51+
if (registeredObject.Instance == null)
52+
{
53+
throw new MissingMethodException();
54+
}
55+
}
56+
if (resolvingTypes != null)
57+
{
58+
resolvingTypes.Remove(registeredObject.TypeToResolve);
2759
}
2860
return registeredObject.Instance;
2961
}
3062

31-
private ConstructorInfo ResolveConstructor(RegisteredObject registeredObject)
63+
private IEnumerable<ConstructorInfo> ResolveConstructors(RegisteredObject registeredObject)
3264
{
33-
var constructors = registeredObject.GetType().GetConstructors();
65+
var constructors = registeredObject.ConcreteType.GetConstructors();
3466
//with DependencyConstructor attribute
3567
var dependencyConstructor =
3668
constructors.FirstOrDefault(
3769
ci => ci.GetCustomAttribute<DependencyConstructorAttribute>() != null);
3870
if (dependencyConstructor != null)
3971
{
40-
return dependencyConstructor;
41-
}
42-
43-
var defaultContructor = constructors.OrderBy(ci => ci.GetParameters().Count()).FirstOrDefault();
44-
if (defaultContructor == null)
72+
yield return dependencyConstructor;
73+
}
74+
var defaultConstructors = constructors.OrderBy(ci => ci.GetParameters().Count());
75+
if (!defaultConstructors.Any())
4576
{
4677
throw new MissingMethodException();
4778
}
48-
return defaultContructor;
79+
foreach (var constructorInfo in defaultConstructors)
80+
{
81+
yield return constructorInfo;
82+
}
4983
}
5084

51-
private IEnumerable<object> ResolveConstructorParameters(ConstructorInfo constructorInfo)
52-
{
53-
return constructorInfo.GetParameters()
54-
.Select(parameter => ResolveObject(parameter.ParameterType));
55-
}
5685

57-
private object ResolveObject(Type typeToResolve)
86+
private object ResolveObject(Type typeToResolve, HashSet<Type> resolvingTypes = null)
5887
{
59-
RegisteredObject registeredObject = null;
88+
RegisteredObject registeredObject;
6089

6190
if (!_registeredObjects.TryGetValue(typeToResolve, out registeredObject))
6291
{
63-
throw new TypeNotRegisteredException(string.Format(
64-
"The type {0} has not been registered.", typeToResolve.Name));
92+
if (typeToResolve.IsInterface || typeToResolve.IsAbstract)
93+
{
94+
throw new TypeNotRegisteredException(string.Format(
95+
"The type {0} has not been registered.", typeToResolve.Name));
96+
}
97+
98+
registeredObject = new RegisteredObject(typeToResolve, typeToResolve, LifeCycle.Transient);
6599
}
66-
return GetInstance(registeredObject);
100+
return GetInstance(registeredObject, resolvingTypes);
67101
}
68102

69103
#endregion
@@ -79,10 +113,10 @@ public void RegisterType<TFrom, TTo>(bool singleton = true) where TTo : TFrom
79113
_registeredObjects[typeof (TFrom)] = new RegisteredObject(typeof (TFrom), typeof (TTo),
80114
singleton
81115
? LifeCycle.Singleton
82-
: LifeCycle.Transient);
116+
: LifeCycle.Transient);
83117
}
84118

85-
public T Resolve<T>()
119+
public T Resolve<T>()
86120
{
87121
return (T) ResolveObject(typeof (T));
88122
}

0 commit comments

Comments
 (0)