Skip to content

Commit

Permalink
Added caching around a few reflection hotspots.
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmg committed Jul 5, 2016
1 parent d036632 commit fddd911
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
// OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;

Expand All @@ -36,14 +37,16 @@ public class DefaultConstructorFinder : IConstructorFinder
{
private readonly Func<Type, ConstructorInfo[]> _finder;

private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> DefaultPublicConstructorsCache = new ConcurrentDictionary<Type, ConstructorInfo[]>();

/// <summary>
/// Initializes a new instance of the <see cref="DefaultConstructorFinder" /> class.
/// </summary>
/// <remarks>
/// Default to selecting all public constructors.
/// </remarks>
public DefaultConstructorFinder()
: this(type => type.GetTypeInfo().DeclaredConstructors.Where(c => c.IsPublic).ToArray())
: this(GetDefaultPublicConstructors)
{
}

Expand All @@ -67,5 +70,11 @@ public ConstructorInfo[] FindConstructors(Type targetType)
{
return _finder(targetType);
}

private static ConstructorInfo[] GetDefaultPublicConstructors(Type type)
{
return DefaultPublicConstructorsCache.GetOrAdd(
type, t => t.GetTypeInfo().DeclaredConstructors.Where(c => c.IsPublic).ToArray());
}
}
}
41 changes: 17 additions & 24 deletions src/Autofac/Util/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
// OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
Expand All @@ -34,11 +35,9 @@ namespace Autofac.Util
{
internal static class TypeExtensions
{
public static readonly Type[] EmptyTypes = new Type[0];

private static readonly Type ReadOnlyCollectionType = Type.GetType("System.Collections.Generic.IReadOnlyCollection`1", false);

private static readonly Type ReadOnlyListType = Type.GetType("System.Collections.Generic.IReadOnlyList`1", false);
private static readonly ConcurrentDictionary<Type, bool> IsGenericEnumerableInterfaceCache = new ConcurrentDictionary<Type, bool>();
private static readonly ConcurrentDictionary<Type, bool> IsGenericListOrCollectionInterfaceTypeCache = new ConcurrentDictionary<Type, bool>();
private static readonly ConcurrentDictionary<Tuple<Type, Type>, bool> IsGenericTypeDefinedByCache = new ConcurrentDictionary<Tuple<Type, Type>, bool>();

/// <summary>Returns the first concrete interface supported by the candidate type that
/// closes the provided open generic service type.</summary>
Expand Down Expand Up @@ -70,31 +69,25 @@ private static IEnumerable<Type> TypesAssignableFrom(Type candidateType)

public static bool IsGenericTypeDefinedBy(this Type @this, Type openGeneric)
{
if (@this == null) throw new ArgumentNullException(nameof(@this));
if (openGeneric == null) throw new ArgumentNullException(nameof(openGeneric));

return !@this.GetTypeInfo().ContainsGenericParameters && @this.GetTypeInfo().IsGenericType && @this.GetGenericTypeDefinition() == openGeneric;
return IsGenericTypeDefinedByCache.GetOrAdd(
Tuple.Create(@this, openGeneric),
key => !key.Item1.GetTypeInfo().ContainsGenericParameters
&& key.Item1.GetTypeInfo().IsGenericType
&& key.Item1.GetGenericTypeDefinition() == key.Item2);
}

public static bool IsClosedTypeOf(this Type @this, Type openGeneric)
{
if (@this == null) throw new ArgumentNullException(nameof(@this));
if (openGeneric == null) throw new ArgumentNullException(nameof(openGeneric));

return TypesAssignableFrom(@this).Any(t => t.GetTypeInfo().IsGenericType && !@this.GetTypeInfo().ContainsGenericParameters && t.GetGenericTypeDefinition() == openGeneric);
}

public static bool IsDelegate(this Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));

return type.GetTypeInfo().IsSubclassOf(typeof(Delegate));
}

public static Type FunctionReturnType(this Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));

var invoke = type.GetTypeInfo().GetDeclaredMethod("Invoke");
Enforce.NotNull(invoke);
return invoke.ReturnType;
Expand Down Expand Up @@ -177,22 +170,22 @@ private static bool ParameterEqualsConstraint(Type parameter, Type constraint)

public static bool IsGenericEnumerableInterfaceType(this Type type)
{
return type.IsGenericTypeDefinedBy(typeof(IEnumerable<>))
|| type.IsGenericListOrCollectionInterfaceType();
return IsGenericEnumerableInterfaceCache.GetOrAdd(
type, t => type.IsGenericTypeDefinedBy(typeof(IEnumerable<>))
|| type.IsGenericListOrCollectionInterfaceType());
}

public static bool IsGenericListOrCollectionInterfaceType(this Type type)
{
return type.IsGenericTypeDefinedBy(typeof(IList<>))
|| type.IsGenericTypeDefinedBy(typeof(ICollection<>))
|| (ReadOnlyCollectionType != null && type.IsGenericTypeDefinedBy(ReadOnlyCollectionType))
|| (ReadOnlyListType != null && type.IsGenericTypeDefinedBy(ReadOnlyListType));
return IsGenericListOrCollectionInterfaceTypeCache.GetOrAdd(
type, t => t.IsGenericTypeDefinedBy(typeof(IList<>))
|| t.IsGenericTypeDefinedBy(typeof(ICollection<>))
|| t.IsGenericTypeDefinedBy(typeof(IReadOnlyCollection<>))
|| t.IsGenericTypeDefinedBy(typeof(IReadOnlyList<>)));
}

public static bool IsCompilerGenerated(this Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));

return type.GetTypeInfo().GetCustomAttributes<CompilerGeneratedAttribute>().Any();
}
}
Expand Down

0 comments on commit fddd911

Please sign in to comment.