Skip to content

Commit 6bcf939

Browse files
committed
Optimizations: Memoize Attributes in AttributeHelper and ServiceRegistrations
Dont use LINQ in ServiceRegistration Don't use LINQ .ToArray() in AttributeHelper.GetAttributes() precompute typeof() in static Optimize ServiceContainer.Create() Optimization: Memoize TypeHelper.GetConstructor() Remove automatically inserted `using System.Diagnostics.CodeAnalysis` Simple formatting private specifier Refactoring User .SequenceEqual() in TYpesComparer Refactor TypesCompares.GetHashCode() Rename TypesEqualityComparer typeofIServiceContainer Optimization: cache ServiceRegistration[] in DomainTypeRegistry public -> private Small optimizations: avoid LINQ in critical places Revert to SequenceEqual in TypesEqualityComparer.Equals() Remove comment reorder public/private methods
1 parent 240ec6a commit 6bcf939

File tree

8 files changed

+183
-169
lines changed

8 files changed

+183
-169
lines changed

Orm/Xtensive.Orm/Collections/TypeRegistry.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
using System.Reflection;
1212
using System.Linq;
1313
using Xtensive.Core;
14-
14+
using Xtensive.IoC;
1515

1616
namespace Xtensive.Collections
1717
{
@@ -33,6 +33,7 @@ public class TypeRegistry : LockableBase,
3333
private readonly ITypeRegistrationProcessor processor;
3434
private bool isProcessingPendingActions = false;
3535
private readonly Set<Assembly> assemblies = new Set<Assembly>();
36+
protected ServiceRegistration[] serviceRegistrations;
3637

3738
/// <summary>
3839
/// Gets assemblies containing registered types.
@@ -63,6 +64,7 @@ public void Register(Type type)
6364
else {
6465
if (typeSet.Contains(type))
6566
return;
67+
serviceRegistrations = null;
6668
types.Add(type);
6769
typeSet.Add(type);
6870
assemblies.Add(type.Assembly);

Orm/Xtensive.Orm/IoC/Internals/DefaultServiceContainer.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,7 @@ private IServiceContainer GetContainer(Type serviceType)
3838
return containers.GetValue(assembly, _assembly => {
3939
var typeRegistry = new TypeRegistry(new ServiceTypeRegistrationProcessor());
4040
typeRegistry.Register(_assembly);
41-
return new ServiceContainer(
42-
from type in typeRegistry
43-
from serviceRegistration in ServiceRegistration.CreateAll(type, true)
44-
select serviceRegistration);
41+
return new ServiceContainer(typeRegistry.SelectMany(type => ServiceRegistration.CreateAll(type, true)));
4542
});
4643
}
4744
}

Orm/Xtensive.Orm/IoC/ServiceContainer.cs

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@
1919

2020
namespace Xtensive.IoC
2121
{
22+
using Key = ValueTuple<Type, string>;
23+
2224
/// <summary>
2325
/// Default IoC (inversion of control) container implementation.
2426
/// </summary>
2527
[Serializable]
2628
public class ServiceContainer : ServiceContainerBase
2729
{
28-
private readonly Dictionary<object, List<ServiceRegistration>> types =
29-
new Dictionary<object, List<ServiceRegistration>>();
30+
private static Type typeofIServiceContainer = typeof(IServiceContainer);
31+
32+
private readonly Dictionary<Key, List<ServiceRegistration>> types =
33+
new Dictionary<Key, List<ServiceRegistration>>();
3034
private readonly Dictionary<ServiceRegistration, object> instances =
3135
new Dictionary<ServiceRegistration, object>();
3236
private readonly Dictionary<ServiceRegistration, Pair<ConstructorInfo, ParameterInfo[]>> constructorCache =
@@ -42,14 +46,13 @@ protected override object HandleGet(Type serviceType, string name)
4246
{
4347
// Not very optimal, but...
4448
lock (_lock) {
45-
List<ServiceRegistration> list;
46-
if (!types.TryGetValue(GetKey(serviceType, name), out list))
47-
return null;
48-
if (list.Count == 0)
49+
if (!types.TryGetValue(GetKey(serviceType, name), out var list))
4950
return null;
50-
if (list.Count > 1)
51-
throw new AmbiguousMatchException(Strings.ExMultipleServicesMatchToTheSpecifiedArguments);
52-
return GetOrCreateInstances(list).Single();
51+
return list.Count switch {
52+
0 => null,
53+
1 => GetOrCreateInstances(list).Single(),
54+
_ => throw new AmbiguousMatchException(Strings.ExMultipleServicesMatchToTheSpecifiedArguments)
55+
};
5356
}
5457
}
5558

@@ -58,10 +61,9 @@ protected override IEnumerable<object> HandleGetAll(Type serviceType)
5861
{
5962
// Not very optimal, but...
6063
lock (_lock) {
61-
List<ServiceRegistration> list;
62-
if (!types.TryGetValue(GetKey(serviceType, null), out list))
63-
return EnumerableUtils<object>.Empty;
64-
return GetOrCreateInstances(list);
64+
return types.TryGetValue(GetKey(serviceType, null), out var list)
65+
? GetOrCreateInstances(list)
66+
: Array.Empty<object>();
6567
}
6668
}
6769

@@ -111,13 +113,8 @@ select c
111113

112114
#region Private \ internal methods
113115

114-
private static object GetKey(Type serviceType, string name)
115-
{
116-
if (name.IsNullOrEmpty())
117-
return serviceType;
118-
else
119-
return new ObjectPair(serviceType, name);
120-
}
116+
private static Key GetKey(Type serviceType, string name) =>
117+
new Key(serviceType, string.IsNullOrEmpty(name) ? null : name);
121118

122119
private IEnumerable<object> GetOrCreateInstances(IEnumerable<ServiceRegistration> services)
123120
{
@@ -141,11 +138,9 @@ private IEnumerable<object> GetOrCreateInstances(IEnumerable<ServiceRegistration
141138

142139
private void Register(ServiceRegistration serviceRegistration)
143140
{
144-
List<ServiceRegistration> list;
145141
var key = GetKey(serviceRegistration.Type, serviceRegistration.Name);
146-
if (!types.TryGetValue(key, out list)) {
147-
list = new List<ServiceRegistration>();
148-
types[key] = list;
142+
if (!types.TryGetValue(key, out var list)) {
143+
types[key] = list = new List<ServiceRegistration>();
149144
}
150145
list.Add(serviceRegistration);
151146
}
@@ -201,25 +196,23 @@ public static IServiceContainer Create(Type containerType, object configuration)
201196
public static IServiceContainer Create(Type containerType, object configuration, IServiceContainer parent)
202197
{
203198
ArgumentValidator.EnsureArgumentNotNull(containerType, "containerType");
204-
if (!typeof(IServiceContainer).IsAssignableFrom(containerType))
199+
if (!typeofIServiceContainer.IsAssignableFrom(containerType))
205200
throw new ArgumentException(string.Format(
206-
Strings.ExContainerTypeMustImplementX, typeof(IServiceContainer).GetShortName()), "containerType");
207-
208-
var possibleArgs =
209-
Enumerable.Empty<object[]>()
210-
.Append(new[] { configuration, parent })
211-
.Append(new[] { configuration })
212-
.Append(new[] { parent });
213-
foreach (var args in possibleArgs) {
214-
var ctor = containerType.GetConstructor(args);
215-
if (ctor != null)
216-
return (IServiceContainer) ctor.Invoke(args);
217-
}
218-
219-
throw new ArgumentException(
220-
Strings.ExContainerTypeDoesNotProvideASuitableConstructor, "containerType");
201+
Strings.ExContainerTypeMustImplementX, typeofIServiceContainer.GetShortName()), "containerType");
202+
203+
Type configurationType = configuration?.GetType(),
204+
parentType = parent?.GetType();
205+
return (IServiceContainer)(
206+
FindConstructor(containerType, configurationType, parentType)?.Invoke(new[] { configuration, parent })
207+
?? FindConstructor(containerType, configurationType)?.Invoke(new[] { configuration })
208+
?? FindConstructor(containerType, parentType)?.Invoke(new[] { parent })
209+
?? throw new ArgumentException(Strings.ExContainerTypeDoesNotProvideASuitableConstructor, "containerType")
210+
);
221211
}
222212

213+
private static ConstructorInfo FindConstructor(Type containerType, params Type[] argumentTypes) =>
214+
containerType.GetSingleConstructor(argumentTypes);
215+
223216
#endregion
224217

225218
/// <summary>
@@ -284,10 +277,8 @@ public static IServiceContainer Create(ConfigurationSection section, string name
284277
if (name.IsNullOrEmpty())
285278
name = string.Empty;
286279

287-
ContainerElement configuration = section == null ? null : section.Containers[name];
288-
289-
if (configuration == null)
290-
configuration = new ContainerElement();
280+
ContainerElement configuration = section?.Containers[name]
281+
?? new ContainerElement();
291282

292283
var registrations = new List<ServiceRegistration>();
293284
var typeRegistry = new TypeRegistry(new ServiceTypeRegistrationProcessor());

Orm/Xtensive.Orm/IoC/ServiceRegistration.cs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,24 @@
55
// Created: 2009.10.12
66

77
using System;
8-
using Xtensive.Collections;
8+
using System.Collections.Concurrent;
9+
using System.Collections.Generic;
910
using Xtensive.Core;
10-
using System.Linq;
11-
1211
using Xtensive.Reflection;
1312

1413
namespace Xtensive.IoC
1514
{
15+
using ServiceRegistrationKey = ValueTuple<Type, bool>;
16+
1617
/// <summary>
1718
/// Describes single service mapping entry for <see cref="ServiceContainer"/>.
1819
/// </summary>
1920
[Serializable]
2021
public sealed class ServiceRegistration
2122
{
23+
private static readonly ConcurrentDictionary<ServiceRegistrationKey, ServiceRegistration[]> serviceRegistrationsByType =
24+
new ConcurrentDictionary<ServiceRegistrationKey, ServiceRegistration[]>();
25+
2226
/// <summary>
2327
/// Gets the type of the service.
2428
/// </summary>
@@ -56,10 +60,8 @@ public sealed class ServiceRegistration
5660
/// <returns>
5761
/// An array of <see cref="ServiceRegistration"/> objects.
5862
/// </returns>
59-
public static ServiceRegistration[] CreateAll(Type type)
60-
{
61-
return CreateAll(type, false);
62-
}
63+
public static ServiceRegistration[] CreateAll(Type type) =>
64+
CreateAll(type, false);
6365

6466
/// <summary>
6567
/// Creates an array of <see cref="ServiceRegistration"/> objects
@@ -72,27 +74,24 @@ public static ServiceRegistration[] CreateAll(Type type)
7274
/// <returns>
7375
/// An array of <see cref="ServiceRegistration"/> objects.
7476
/// </returns>
75-
public static ServiceRegistration[] CreateAll(Type type, bool defaultOnly)
76-
{
77+
public static ServiceRegistration[] CreateAll(Type type, bool defaultOnly) =>
78+
serviceRegistrationsByType.GetOrAdd(new ServiceRegistrationKey(type, defaultOnly), ServiceRegistrationsExtractor);
79+
80+
private static readonly Func<ServiceRegistrationKey, ServiceRegistration[]> ServiceRegistrationsExtractor = ((Type type, bool defaultOnly) t) => {
81+
(var type, var defaultOnly) = t;
7782
ArgumentValidator.EnsureArgumentNotNull(type, "type");
7883
if (type.IsAbstract)
79-
return ArrayUtils<ServiceRegistration>.EmptyArray;
84+
return Array.Empty<ServiceRegistration>();
8085

8186
var attributes = type.GetAttributes<ServiceAttribute>(AttributeSearchOptions.InheritNone);
82-
if (attributes == null)
83-
return ArrayUtils<ServiceRegistration>.EmptyArray;
84-
if (defaultOnly)
85-
attributes = attributes.Where(a => a.Default).ToArray();
86-
if (attributes.Length == 0)
87-
return ArrayUtils<ServiceRegistration>.EmptyArray;
88-
89-
var result = new ServiceRegistration[attributes.Length];
90-
for (int i = 0; i < attributes.Length; i++) {
91-
var sa = attributes[i];
92-
result[i] = new ServiceRegistration(sa.Type, sa.Name.IsNullOrEmpty() ? null : sa.Name, type, sa.Singleton);
87+
var registrations = new List<ServiceRegistration>(attributes.Length);
88+
foreach (var sa in attributes) {
89+
if (!defaultOnly || sa.Default) {
90+
registrations.Add(new ServiceRegistration(sa.Type, sa.Name.IsNullOrEmpty() ? null : sa.Name, type, sa.Singleton));
91+
}
9392
}
94-
return result;
95-
}
93+
return registrations.ToArray();
94+
};
9695

9796

9897
// Constructors

Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Collections.Generic;
99
using Xtensive.Collections;
1010
using System.Linq;
11+
using Xtensive.IoC;
1112
using Xtensive.Orm.Internals;
1213
using Xtensive.Orm.Upgrade;
1314

@@ -42,6 +43,9 @@ public class DomainTypeRegistry : TypeRegistry
4243
/// </summary>
4344
public IEnumerable<Type> SessionServices => this.Where(IsSessionService);
4445

46+
public ServiceRegistration[] ServiceRegistrations =>
47+
serviceRegistrations ??= SessionServices.SelectMany(ServiceRegistration.CreateAll).ToArray();
48+
4549
/// <summary>
4650
/// Gets all the registered <see cref="IModule"/> implementations.
4751
/// </summary>

Orm/Xtensive.Orm/Orm/Session.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ public partial class Session : DomainBound,
7070
private const string IdentifierFormat = "#{0}";
7171
private const string FullNameFormat = "{0}, #{1}";
7272

73+
private static readonly Type
74+
typeofSession = typeof(Session),
75+
typeofSessionConfiguration = typeof(SessionConfiguration),
76+
typeofSessionHandler = typeof(SessionHandler),
77+
typeofServiceContainer = typeof(ServiceContainer);
78+
7379
private static Func<Session> resolver;
7480
private static long lastUsedIdentifier;
7581

@@ -291,18 +297,18 @@ private EnumerationContextOptions GetEnumerationContextOptions()
291297
private IServiceContainer CreateSystemServices()
292298
{
293299
var registrations = new List<ServiceRegistration>{
294-
new ServiceRegistration(typeof (Session), this),
295-
new ServiceRegistration(typeof (SessionConfiguration), Configuration),
296-
new ServiceRegistration(typeof (SessionHandler), Handler),
300+
new ServiceRegistration(typeofSession, this),
301+
new ServiceRegistration(typeofSessionConfiguration, Configuration),
302+
new ServiceRegistration(typeofSessionHandler, Handler),
297303
};
298304
Handler.AddSystemServices(registrations);
299305
return new ServiceContainer(registrations, Domain.Services);
300306
}
301307

302308
private IServiceContainer CreateServices()
303309
{
304-
var userContainerType = Configuration.ServiceContainerType ?? typeof(ServiceContainer);
305-
var registrations = Domain.Configuration.Types.SessionServices.SelectMany(ServiceRegistration.CreateAll);
310+
var userContainerType = Configuration.ServiceContainerType ?? typeofServiceContainer;
311+
var registrations = Domain.Configuration.Types.ServiceRegistrations;
306312
var systemContainer = CreateSystemServices();
307313
var userContainer = ServiceContainer.Create(userContainerType, systemContainer);
308314
return new ServiceContainer(registrations, userContainer);

0 commit comments

Comments
 (0)