Skip to content

Commit f1bc32b

Browse files
committed
Reduce amount of iteraion over all loaded assemblies
1 parent 3509947 commit f1bc32b

8 files changed

Lines changed: 91 additions & 129 deletions

File tree

src/UnityContainerAttributeRegistration/Attribute/RegisterFactoryAttribute.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
using JetBrains.Annotations;
44

5-
using Unity.Lifetime;
6-
75

86
namespace UnityContainerAttributeRegistration.Attribute
97
{

src/UnityContainerAttributeRegistration/Populator/FactoryPopulator.cs

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,14 @@
99
using Unity.Lifetime;
1010

1111
using UnityContainerAttributeRegistration.Attribute;
12-
using UnityContainerAttributeRegistration.Exention;
13-
using UnityContainerAttributeRegistration.Provider;
1412

1513

1614
namespace UnityContainerAttributeRegistration.Populator
1715
{
1816
internal class FactoryPopulator : Populator
1917
{
20-
public FactoryPopulator(IAssemblyProvider assemblyProvider) : base(assemblyProvider)
18+
public override IUnityContainer Populate(IUnityContainer container, IList<Type> typesWithAttribute)
2119
{
22-
}
23-
24-
public override IUnityContainer Populate(IUnityContainer container)
25-
{
26-
IList<Type> typesWithAttribute = GetTypesWith<RegisterProviderAttribute>(TypeDefined.Inherit)
27-
.ToList();
28-
2920
IEnumerable<FactoryToRegister> factoriesToRegister =
3021
typesWithAttribute.SelectMany(providerClassType => GetInstancesToRegisterFor(container, providerClassType));
3122

@@ -43,13 +34,6 @@ public override IUnityContainer Populate(IUnityContainer container)
4334

4435
private IEnumerable<FactoryToRegister> GetInstancesToRegisterFor(IUnityContainer container, Type providerClassType)
4536
{
46-
if(providerClassType.IsStatic() || providerClassType.IsAbstract)
47-
{
48-
// todo is not covered, exception is thrown by another populator
49-
throw new InvalidOperationException(
50-
$"Class type must not be static or abstract to be used with RegisterTypeAttribute: {providerClassType.FullName}");
51-
}
52-
5337
object providerClassInstance = container.Resolve(providerClassType);
5438
MethodInfo[] methodInfos = providerClassType.GetMethods();
5539

@@ -69,7 +53,7 @@ private FactoryToRegister CreateFactoryToRegisterFrom(MethodInfo info, object in
6953
throw new InvalidOperationException("Return type must not be void.");
7054
}
7155

72-
if(!IsUnityFactorySignatur(info))
56+
if(!IsUnityFactorySignature(info))
7357
{
7458
throw new InvalidOperationException("Factory method signature does not match.");
7559
}
@@ -83,27 +67,22 @@ private FactoryToRegister CreateFactoryToRegisterFrom(MethodInfo info, object in
8367
return new FactoryToRegister(returnType, GetFactoryMethodFor(info, instance), lifetimeManager);
8468
}
8569

86-
private bool IsUnityFactorySignatur(MethodInfo methodInfo)
70+
private bool IsUnityFactorySignature(MethodInfo methodInfo)
8771
{
8872
var parameters = methodInfo.GetParameters();
8973

90-
if(parameters.Length == 1
91-
&& parameters[0].ParameterType == typeof(IUnityContainer)
92-
)
74+
switch(parameters.Length)
9375
{
94-
return true;
76+
case 1 when parameters[0].ParameterType == typeof(IUnityContainer):
77+
case 3 when parameters[0].ParameterType == typeof(IUnityContainer) && parameters[1].ParameterType == typeof(Type) && parameters[2].ParameterType == typeof(string):
78+
{
79+
return true;
80+
}
81+
default:
82+
{
83+
return false;
84+
}
9585
}
96-
97-
if(parameters.Length == 3
98-
&& parameters[0].ParameterType == typeof(IUnityContainer)
99-
&& parameters[1].ParameterType == typeof(Type)
100-
&& parameters[2].ParameterType == typeof(string)
101-
)
102-
{
103-
return true;
104-
}
105-
106-
return false;
10786
}
10887

10988
private Func<IUnityContainer, Type, string, object> GetFactoryMethodFor(MethodInfo methodInfo, object instance)

src/UnityContainerAttributeRegistration/Populator/IPopulator.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using Unity;
1+
using System;
2+
using System.Collections.Generic;
3+
4+
using Unity;
25

36

47
namespace UnityContainerAttributeRegistration.Populator
@@ -12,7 +15,8 @@ internal interface IPopulator
1215
/// Populate the passed <paramref name="container" />.
1316
/// </summary>
1417
/// <param name="container"><see cref="IUnityContainer" /> to populate.</param>
18+
/// <param name="typesWith"></param>
1519
/// <returns>Passed <paramref name="container" />.</returns>
16-
IUnityContainer Populate(IUnityContainer container);
20+
IUnityContainer Populate(IUnityContainer container, IList<Type> typesWith);
1721
}
1822
}

src/UnityContainerAttributeRegistration/Populator/InstancePopulator.cs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
using UnityContainerAttributeRegistration.Provider;
1212
using UnityContainerAttributeRegistration.Attribute;
13-
using UnityContainerAttributeRegistration.Exention;
1413

1514

1615
namespace UnityContainerAttributeRegistration.Populator
@@ -20,25 +19,10 @@ namespace UnityContainerAttributeRegistration.Populator
2019
/// </summary>
2120
internal class InstancePopulator : Populator
2221
{
23-
/// <summary>
24-
/// ctor
25-
/// </summary>
26-
/// <param name="appDomain">Used <see cref="IAssemblyProvider" /> for searching for candidates.</param>
27-
public InstancePopulator(IAssemblyProvider appDomain) : base(appDomain)
28-
{
29-
}
30-
31-
/// <summary>
32-
/// Populate the passed <paramref name="container" />.
33-
/// </summary>
34-
/// <param name="container"><see cref="IUnityContainer" /> to populate.</param>
35-
/// <returns>Passed <paramref name="container" />.</returns>
22+
/// <inheritdoc cref="Populator"/>
3623
/// <exception cref="InvalidOperationException">Class type must not be static or abstract.</exception>
37-
public override IUnityContainer Populate(IUnityContainer container)
24+
public override IUnityContainer Populate(IUnityContainer container, IList<Type> typesWithAttribute)
3825
{
39-
IList<Type> typesWithAttribute = GetTypesWith<RegisterProviderAttribute>(TypeDefined.Inherit)
40-
.ToList();
41-
4226
IEnumerable<InstanceToRegister> instancesToRegister =
4327
typesWithAttribute.SelectMany(providerClassType => GetInstancesToRegisterFor(container, providerClassType));
4428

@@ -62,12 +46,6 @@ public override IUnityContainer Populate(IUnityContainer container)
6246
/// <exception cref="InvalidOperationException"><paramref name="providerClassType" /> type must not be static or abstract.</exception>
6347
private IEnumerable<InstanceToRegister> GetInstancesToRegisterFor(IUnityContainer container, Type providerClassType)
6448
{
65-
if(providerClassType.IsStatic() || providerClassType.IsAbstract)
66-
{
67-
throw new InvalidOperationException(
68-
$"Class type must not be static or abstract to be used with RegisterTypeAttribute: {providerClassType.FullName}");
69-
}
70-
7149
object providerClassInstance = container.Resolve(providerClassType);
7250
PropertyInfo[] properties = providerClassType.GetProperties();
7351

src/UnityContainerAttributeRegistration/Populator/Populator.cs

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Linq;
43
using System.Reflection;
54

65
using JetBrains.Annotations;
76

87
using Unity;
98

10-
using UnityContainerAttributeRegistration.Provider;
11-
129

1310
namespace UnityContainerAttributeRegistration.Populator
1411
{
@@ -17,33 +14,8 @@ namespace UnityContainerAttributeRegistration.Populator
1714
/// </summary>
1815
internal abstract class Populator : IPopulator
1916
{
20-
private readonly IAssemblyProvider assemblyProvider;
21-
22-
/// <summary>
23-
/// ctor
24-
/// </summary>
25-
/// <param name="assemblyProvider">Used <see cref="IAssemblyProvider" /> for searching for candidates.</param>
26-
protected Populator(IAssemblyProvider assemblyProvider)
27-
{
28-
this.assemblyProvider = assemblyProvider;
29-
}
30-
3117
/// <inheritdoc cref="IPopulator.Populate" />
32-
public abstract IUnityContainer Populate(IUnityContainer container);
33-
34-
/// <summary>
35-
/// Find all types using <typeparamref name="TAttribute" />.
36-
/// </summary>
37-
/// <param name="typeDefined">Using inheritance or not.</param>
38-
/// <typeparam name="TAttribute"><see cref="System.Attribute" /> used by searched <see cref="Type" />s.</typeparam>
39-
/// <returns>List of all <see cref="Type" />s in an <see cref="IAssemblyProvider" /> using <typeparamref name="TAttribute" />.</returns>
40-
protected IEnumerable<Type> GetTypesWith<TAttribute>(TypeDefined typeDefined) where TAttribute : System.Attribute
41-
{
42-
return assemblyProvider.GetAssemblies()
43-
.SelectMany(assembly => assembly.GetTypes())
44-
.Where(type => type.IsDefined(typeof(TAttribute), typeDefined == TypeDefined.Inherit))
45-
;
46-
}
18+
public abstract IUnityContainer Populate(IUnityContainer container, IList<Type> typesWithAttribute);
4719

4820
/// <summary>
4921
/// Create an instance for <paramref name="objectType" />.

src/UnityContainerAttributeRegistration/Populator/TypePopulator.cs

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Linq;
43
using System.Reflection;
54

65
using Unity;
76
using Unity.Lifetime;
87

98
using UnityContainerAttributeRegistration.Attribute;
10-
using UnityContainerAttributeRegistration.Exention;
11-
using UnityContainerAttributeRegistration.Provider;
129

1310

1411
namespace UnityContainerAttributeRegistration.Populator
@@ -18,35 +15,12 @@ namespace UnityContainerAttributeRegistration.Populator
1815
/// </summary>
1916
internal class TypePopulator : Populator
2017
{
21-
/// <summary>
22-
/// ctor
23-
/// </summary>
24-
/// <param name="assemblyProvider">
25-
/// Used <see cref="IAssemblyProvider" /> to find all candidates using <see cref="RegisterTypeAttribute" />
26-
/// </param>
27-
public TypePopulator(IAssemblyProvider assemblyProvider) : base(assemblyProvider)
28-
{
29-
}
30-
31-
/// <summary>
32-
/// Populate the passed <paramref name="container" />.
33-
/// </summary>
34-
/// <param name="container"><see cref="IUnityContainer" /> to populate.</param>
35-
/// <returns>Passed <paramref name="container" />.</returns>
18+
/// <inheritdoc cref="Populator"/>
3619
/// <exception cref="InvalidOperationException">Class type must not be static or abstract.</exception>
37-
public override IUnityContainer Populate(IUnityContainer container)
20+
public override IUnityContainer Populate(IUnityContainer container, IList<Type> typesWithAttribute)
3821
{
39-
IList<Type> typesWithAttribute = GetTypesWith<RegisterTypeAttribute>(TypeDefined.Inherit)
40-
.ToList();
41-
4222
foreach(Type to in typesWithAttribute)
4323
{
44-
if(to.IsStatic() || to.IsAbstract)
45-
{
46-
throw new InvalidOperationException(
47-
$"Class type must not be static or abstract to be used with RegisterTypeAttribute: {to.FullName}");
48-
}
49-
5024
RegisterTypeAttribute attribute = to.GetCustomAttribute<RegisterTypeAttribute>();
5125
ITypeLifetimeManager lifetimeManager = attribute.LifetimeManager == null
5226
? null

src/UnityContainerAttributeRegistration/UnityContainerPopulator.cs

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
using JetBrains.Annotations;
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
using JetBrains.Annotations;
26

37
using Unity;
48

9+
using UnityContainerAttributeRegistration.Attribute;
10+
using UnityContainerAttributeRegistration.Exention;
511
using UnityContainerAttributeRegistration.Populator;
612
using UnityContainerAttributeRegistration.Provider;
713

@@ -13,9 +19,17 @@ namespace UnityContainerAttributeRegistration
1319
/// </summary>
1420
public sealed class UnityContainerPopulator
1521
{
16-
private readonly IPopulator typePopulator;
17-
private readonly IPopulator instancePopulator;
18-
private readonly IPopulator factoryPopulator;
22+
[NotNull]
23+
private readonly IAssemblyProvider appDomain;
24+
25+
[NotNull]
26+
private readonly IPopulator typePopulator;
27+
28+
[NotNull]
29+
private readonly IPopulator instancePopulator;
30+
31+
[NotNull]
32+
private readonly IPopulator factoryPopulator;
1933

2034
/// <summary>
2135
/// Use <see cref="System.AppDomain.CurrentDomain" /> to populate an <see cref="Unity.IUnityContainer" />
@@ -30,9 +44,10 @@ public UnityContainerPopulator() : this(new AssemblyProvider())
3044
/// <param name="appDomain">Custom <see cref="IAssemblyProvider" /></param>
3145
public UnityContainerPopulator([NotNull] IAssemblyProvider appDomain)
3246
{
33-
typePopulator = new TypePopulator(appDomain);
34-
instancePopulator = new InstancePopulator(appDomain);
35-
factoryPopulator = new FactoryPopulator(appDomain);
47+
this.appDomain = appDomain;
48+
typePopulator = new TypePopulator();
49+
instancePopulator = new InstancePopulator();
50+
factoryPopulator = new FactoryPopulator();
3651
}
3752

3853
/// <summary>
@@ -53,11 +68,50 @@ public IUnityContainer Populate()
5368
/// </returns>
5469
public IUnityContainer Populate([NotNull] IUnityContainer container)
5570
{
56-
typePopulator.Populate(container);
57-
instancePopulator.Populate(container);
58-
factoryPopulator.Populate(container);
71+
IDictionary<Type, IList<Type>> annotatedTypes = FindAnnotatedTypes(TypeDefined.Inherit);
72+
73+
typePopulator.Populate(container, annotatedTypes[typeof(RegisterTypeAttribute)]);
74+
instancePopulator.Populate(container, annotatedTypes[typeof(RegisterProviderAttribute)]);
75+
factoryPopulator.Populate(container, annotatedTypes[typeof(RegisterProviderAttribute)]);
5976

6077
return container;
6178
}
79+
80+
private IDictionary<Type, IList<Type>> FindAnnotatedTypes(TypeDefined typeDefined)
81+
{
82+
IEnumerable<Type> types = appDomain.GetAssemblies()
83+
.SelectMany(assembly => assembly.GetTypes());
84+
85+
IDictionary<Type, IList<Type>> typesPerAttribute = new Dictionary<Type, IList<Type>>()
86+
{
87+
{typeof(RegisterTypeAttribute), new List<Type>()},
88+
{typeof(RegisterProviderAttribute), new List<Type>()}
89+
};
90+
91+
foreach(Type classType in types)
92+
{
93+
// todo avoid nested loop
94+
#pragma warning disable AV1532
95+
foreach(KeyValuePair<Type, IList<Type>> kv in typesPerAttribute)
96+
#pragma warning restore AV1532
97+
{
98+
Type attributeType = kv.Key;
99+
IList<Type> typesWithAttribute = kv.Value;
100+
101+
if (classType.IsDefined(attributeType, typeDefined == TypeDefined.Inherit))
102+
{
103+
if(classType.IsStatic() || classType.IsAbstract)
104+
{
105+
throw new InvalidOperationException(
106+
$"Class type must not be static or abstract to be used with RegisterTypeAttribute: {classType.FullName}");
107+
}
108+
109+
typesWithAttribute.Add(classType);
110+
}
111+
}
112+
}
113+
114+
return typesPerAttribute;
115+
}
62116
}
63117
}

src/UnityContainerAttributeRegistrationTest/Attribute/RegisterFactoryAttributeTest.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ public void TestPopulate(Type providerType, Type expectedFrom, Type expectedTo,
4444
AreEqual(2, result.Count);
4545
IsUnityContainerRegistration(result[0]);
4646
IsExpectedRegisteredContainer(result[1], expectedFrom, expectedTo, expectedFactoryLifetimeManagerType);
47+
48+
object obj = container.Resolve(expectedTo);
49+
NotNull(obj);
4750
}
4851

4952
[Test]

0 commit comments

Comments
 (0)