Skip to content

Commit

Permalink
Reduce impact of extra collection pass
Browse files Browse the repository at this point in the history
Assuming that default interface methods are relatively rare, if we keep
track of which interfaces contain any of them at all, we can then limit
our extra pass during class proxy generation to just those interfaces
and exclude the rest (i.e. hopefully the majority).
  • Loading branch information
stakx committed Aug 31, 2023
1 parent a8d258f commit 2b2e97e
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ protected override IEnumerable<MembersCollector> GetCollectors()

foreach (var @interface in targetType.GetAllInterfaces())
{
if (@interface.HasAnyOverridableDefaultImplementations() == false)
{
continue;
}

yield return new InterfaceMembersWithDefaultImplementationCollector(@interface, targetType);
}

Expand Down
27 changes: 27 additions & 0 deletions src/Castle.Core/DynamicProxy/Internal/TypeUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace Castle.DynamicProxy.Internal
public static class TypeUtil
{
private static readonly Dictionary<Type, MethodInfo[]> instanceMethodsCache = new Dictionary<Type, MethodInfo[]>();
private static readonly Dictionary<Type, bool> hasAnyOverridableDefaultImplementationsCache = new Dictionary<Type, bool>();

internal static bool IsNullableType(this Type type)
{
Expand Down Expand Up @@ -134,6 +135,32 @@ public static Type GetTypeOrNull(object target)
return target.GetType();
}

internal static bool HasAnyOverridableDefaultImplementations(this Type interfaceType)
{
Debug.Assert(interfaceType != null);
Debug.Assert(interfaceType.IsInterface);

var cache = hasAnyOverridableDefaultImplementationsCache;
lock (cache)
{
if (!cache.TryGetValue(interfaceType, out var result))
{
foreach (var method in interfaceType.GetAllInstanceMethods())
{
if (method.IsAbstract == false && method.IsFinal == false && method.IsVirtual)
{
result = true;
break;
}
}

cache[interfaceType] = result;
}

return result;
}
}

internal static Type[] AsTypeArray(this GenericTypeParameterBuilder[] typeInfos)
{
Type[] types = new Type[typeInfos.Length];
Expand Down

0 comments on commit 2b2e97e

Please sign in to comment.