Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added visitor factory cache #15

Merged
merged 1 commit into from
Apr 29, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions src/Abioc/Composition/VisitorFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
namespace Abioc.Composition
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Abioc.Registration;

Expand All @@ -18,6 +20,9 @@ internal static class VisitorFactory

private static readonly Lazy<Type[]> GenericVisitorTypes = new Lazy<Type[]>(GetGenericVisitorTypes);

private static readonly ConcurrentDictionary<Type, Func<object>[]> VisitorFactoryCache =
new ConcurrentDictionary<Type, Func<object>[]>();

/// <summary>
/// Creates the visitors that are <see cref="TypeInfo.IsAssignableFrom(TypeInfo)"/> to the specified type.
/// </summary>
Expand All @@ -27,6 +32,20 @@ internal static class VisitorFactory
/// </returns>
public static IEnumerable<IRegistrationVisitor<TRegistration>> CreateVisitors<TRegistration>()
where TRegistration : class, IRegistration
{
Type visitorType = typeof(IRegistrationVisitor<TRegistration>);

Func<object>[] nonTypedFactories =
VisitorFactoryCache.GetOrAdd(visitorType, t => CreateVisitorFactories<TRegistration>());

IEnumerable<Func<IRegistrationVisitor<TRegistration>>> factories =
nonTypedFactories.Cast<Func<IRegistrationVisitor<TRegistration>>>();

return factories.Select(f => f());
}

private static Func<object>[] CreateVisitorFactories<TRegistration>()
where TRegistration : class, IRegistration
{
TypeInfo visitorTypeInfo = typeof(IRegistrationVisitor<TRegistration>).GetTypeInfo();
TypeInfo registrationTypeInfo = typeof(TRegistration).GetTypeInfo();
Expand All @@ -37,8 +56,8 @@ public static IEnumerable<IRegistrationVisitor<TRegistration>> CreateVisitors<TR
// Get the non generic types that are assignable to the visitor type.
IEnumerable<Type> types = NonGenericVisitorTypes.Value.Where(visitorTypeInfo.IsAssignableFrom);

// Create the visitors.
return types.Select(Activator.CreateInstance).Cast<IRegistrationVisitor<TRegistration>>();
// Create the visitor factories.
return types.Select(CreateVisitorFactory<TRegistration>).Cast<Func<object>>().ToArray();
}

// Get the generic arguments of the registration type.
Expand All @@ -55,8 +74,23 @@ public static IEnumerable<IRegistrationVisitor<TRegistration>> CreateVisitors<TR
.Select(gt => gt.GetTypeInfo().MakeGenericType(typeArguments))
.Where(visitorTypeInfo.IsAssignableFrom);

// Create the visitors.
return genericTypes.Select(Activator.CreateInstance).Cast<IRegistrationVisitor<TRegistration>>();
// Create the visitor factories.
return genericTypes.Select(CreateVisitorFactory<TRegistration>).Cast<Func<object>>().ToArray();
}

private static Func<IRegistrationVisitor<TRegistration>> CreateVisitorFactory<TRegistration>(Type type)
where TRegistration : class, IRegistration
{
if (type == null)
throw new ArgumentNullException(nameof(type));

ConstructorInfo constructorInfo = type.GetTypeInfo().GetConstructor(Type.EmptyTypes);

Func<IRegistrationVisitor<TRegistration>> factory =
Expression.Lambda<Func<IRegistrationVisitor<TRegistration>>>(Expression.New(constructorInfo))
.Compile();

return factory;
}

private static IEnumerable<Type> GetAllVisitorTypes()
Expand Down