Skip to content

Commit

Permalink
Skip unnecessary contributors during proxy type generation (#552)
Browse files Browse the repository at this point in the history
1. Build `contributors` list incrementally

For interface proxy generators, the order of contributors doesn't match
the documented order of precedence, so we fix that here.

2. Skip certain contributors when not needed

3. Some finishing touches

 * Reorder code for more logical grouping.
 * Use the same contributor names across both `BaseClassProxyGenerator`
   and `BaseInterfaceProxyGenerator`.
  • Loading branch information
stakx committed Jan 5, 2021
1 parent f2a75e0 commit eae5dc3
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 66 deletions.
78 changes: 41 additions & 37 deletions src/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,21 +100,24 @@ protected sealed override Type GenerateType(string name, INamingScope namingScop

private IEnumerable<Type> GetTypeImplementerMapping(out IEnumerable<ITypeContributor> contributors, INamingScope namingScope)
{
var methodsToSkip = new List<MethodInfo>();
var proxyInstance = GetProxyInstanceContributor(methodsToSkip);
// TODO: the trick with methodsToSkip is not very nice...
var proxyTarget = GetProxyTargetContributor(methodsToSkip, namingScope);
IDictionary<Type, ITypeContributor> typeImplementerMapping = new Dictionary<Type, ITypeContributor>();
var contributorsList = new List<ITypeContributor>(capacity: 4);
var methodsToSkip = new List<MethodInfo>(); // TODO: the trick with methodsToSkip is not very nice...
var targetInterfaces = targetType.GetAllInterfaces();
var typeImplementerMapping = new Dictionary<Type, ITypeContributor>();

// Order of interface precedence:

// 1. first target
// target is not an interface so we do nothing
var targetContributor = GetProxyTargetContributor(methodsToSkip, namingScope);
contributorsList.Add(targetContributor);

var targetInterfaces = targetType.GetAllInterfaces();
// 2. then mixins
var mixins = new MixinContributor(namingScope, false) { Logger = Logger };
if (ProxyGenerationOptions.HasMixins)
{
var mixinContributor = new MixinContributor(namingScope, false) { Logger = Logger };
contributorsList.Add(mixinContributor);

foreach (var mixinInterface in ProxyGenerationOptions.MixinData.MixinInterfaces)
{
if (targetInterfaces.Contains(mixinInterface))
Expand All @@ -123,68 +126,69 @@ private IEnumerable<Type> GetTypeImplementerMapping(out IEnumerable<ITypeContrib
if (interfaces.Contains(mixinInterface) &&
typeImplementerMapping.ContainsKey(mixinInterface) == false)
{
AddMappingNoCheck(mixinInterface, proxyTarget, typeImplementerMapping);
proxyTarget.AddInterfaceToProxy(mixinInterface);
AddMappingNoCheck(mixinInterface, targetContributor, typeImplementerMapping);
targetContributor.AddInterfaceToProxy(mixinInterface);
}
// we do not intercept the interface
mixins.AddEmptyInterface(mixinInterface);
mixinContributor.AddEmptyInterface(mixinInterface);
}
else
{
if (!typeImplementerMapping.ContainsKey(mixinInterface))
{
mixins.AddInterfaceToProxy(mixinInterface);
AddMappingNoCheck(mixinInterface, mixins, typeImplementerMapping);
mixinContributor.AddInterfaceToProxy(mixinInterface);
AddMappingNoCheck(mixinInterface, mixinContributor, typeImplementerMapping);
}
}
}
}
var additionalInterfacesContributor = new InterfaceProxyWithoutTargetContributor(namingScope,
(c, m) => NullExpression.Instance)
{ Logger = Logger };

// 3. then additional interfaces
foreach (var @interface in interfaces)
if (interfaces.Length > 0)
{
if (targetInterfaces.Contains(@interface))
var additionalInterfacesContributor = new InterfaceProxyWithoutTargetContributor(namingScope, (c, m) => NullExpression.Instance) { Logger = Logger };
contributorsList.Add(additionalInterfacesContributor);

foreach (var @interface in interfaces)
{
if (typeImplementerMapping.ContainsKey(@interface))
if (targetInterfaces.Contains(@interface))
{
continue;
}
if (typeImplementerMapping.ContainsKey(@interface))
{
continue;
}

// we intercept the interface, and forward calls to the target type
AddMappingNoCheck(@interface, proxyTarget, typeImplementerMapping);
proxyTarget.AddInterfaceToProxy(@interface);
}
else if (ProxyGenerationOptions.MixinData.ContainsMixin(@interface) == false)
{
additionalInterfacesContributor.AddInterfaceToProxy(@interface);
AddMapping(@interface, additionalInterfacesContributor, typeImplementerMapping);
// we intercept the interface, and forward calls to the target type
AddMappingNoCheck(@interface, targetContributor, typeImplementerMapping);
targetContributor.AddInterfaceToProxy(@interface);
}
else if (ProxyGenerationOptions.MixinData.ContainsMixin(@interface) == false)
{
additionalInterfacesContributor.AddInterfaceToProxy(@interface);
AddMapping(@interface, additionalInterfacesContributor, typeImplementerMapping);
}
}
}

// 4. plus special interfaces
var instanceContributor = GetProxyInstanceContributor(methodsToSkip);
contributorsList.Add(instanceContributor);
#if FEATURE_SERIALIZATION
if (targetType.IsSerializable)
{
AddMappingForISerializable(typeImplementerMapping, proxyInstance);
AddMappingForISerializable(typeImplementerMapping, instanceContributor);
}
#endif
try
{
AddMappingNoCheck(typeof(IProxyTargetAccessor), proxyInstance, typeImplementerMapping);
AddMappingNoCheck(typeof(IProxyTargetAccessor), instanceContributor, typeImplementerMapping);
}
catch (ArgumentException)
{
HandleExplicitlyPassedProxyTargetAccessor(targetInterfaces);
}

contributors = new List<ITypeContributor>
{
proxyTarget,
mixins,
additionalInterfacesContributor,
proxyInstance
};
contributors = contributorsList;
return typeImplementerMapping.Keys;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,21 @@ protected override Type GenerateType(string typeName, INamingScope namingScope)
out IEnumerable<ITypeContributor> contributors,
INamingScope namingScope)
{
IDictionary<Type, ITypeContributor> typeImplementerMapping = new Dictionary<Type, ITypeContributor>();
var mixins = new MixinContributor(namingScope, AllowChangeTarget) { Logger = Logger };
var contributorsList = new List<ITypeContributor>(capacity: 4);
var targetInterfaces = proxyTargetType.GetAllInterfaces();
var typeImplementerMapping = new Dictionary<Type, ITypeContributor>();

// Order of interface precedence:
// 1. first target
var targetInterfaces = proxyTargetType.GetAllInterfaces();
var target = AddMappingForTargetType(typeImplementerMapping, proxyTargetType, targetInterfaces, namingScope);
var targetContributor = AddMappingForTargetType(typeImplementerMapping, proxyTargetType, targetInterfaces, namingScope);
contributorsList.Add(targetContributor);

// 2. then mixins
if (ProxyGenerationOptions.HasMixins)
{
var mixinContributor = new MixinContributor(namingScope, AllowChangeTarget) { Logger = Logger };
contributorsList.Add(mixinContributor);

foreach (var mixinInterface in ProxyGenerationOptions.MixinData.MixinInterfaces)
{
if (targetInterfaces.Contains(mixinInterface))
Expand All @@ -164,60 +169,60 @@ protected override Type GenerateType(string typeName, INamingScope namingScope)
if (interfaces.Contains(mixinInterface))
{
// we intercept the interface, and forward calls to the target type
AddMapping(mixinInterface, target, typeImplementerMapping);
AddMapping(mixinInterface, targetContributor, typeImplementerMapping);
}
// we do not intercept the interface
mixins.AddEmptyInterface(mixinInterface);
mixinContributor.AddEmptyInterface(mixinInterface);
}
else
{
if (!typeImplementerMapping.ContainsKey(mixinInterface))
{
mixins.AddInterfaceToProxy(mixinInterface);
typeImplementerMapping.Add(mixinInterface, mixins);
mixinContributor.AddInterfaceToProxy(mixinInterface);
typeImplementerMapping.Add(mixinInterface, mixinContributor);
}
}
}
}

var additionalInterfacesContributor = GetContributorForAdditionalInterfaces(namingScope);
// 3. then additional interfaces
foreach (var @interface in interfaces)
if (interfaces.Length > 0)
{
if (typeImplementerMapping.ContainsKey(@interface))
{
continue;
}
if (ProxyGenerationOptions.MixinData.ContainsMixin(@interface))
var additionalInterfacesContributor = GetContributorForAdditionalInterfaces(namingScope);
contributorsList.Add(additionalInterfacesContributor);

foreach (var @interface in interfaces)
{
continue;
}
if (typeImplementerMapping.ContainsKey(@interface))
{
continue;
}
if (ProxyGenerationOptions.MixinData.ContainsMixin(@interface))
{
continue;
}

additionalInterfacesContributor.AddInterfaceToProxy(@interface);
AddMappingNoCheck(@interface, additionalInterfacesContributor, typeImplementerMapping);
additionalInterfacesContributor.AddInterfaceToProxy(@interface);
AddMappingNoCheck(@interface, additionalInterfacesContributor, typeImplementerMapping);
}
}

// 4. plus special interfaces
var instance = new InterfaceProxyInstanceContributor(targetType, GeneratorType, interfaces);
var instanceContributor = new InterfaceProxyInstanceContributor(targetType, GeneratorType, interfaces);
contributorsList.Add(instanceContributor);
#if FEATURE_SERIALIZATION
AddMappingForISerializable(typeImplementerMapping, instance);
AddMappingForISerializable(typeImplementerMapping, instanceContributor);
#endif
try
{
AddMappingNoCheck(typeof(IProxyTargetAccessor), instance, typeImplementerMapping);
AddMappingNoCheck(typeof(IProxyTargetAccessor), instanceContributor, typeImplementerMapping);
}
catch (ArgumentException)
{
HandleExplicitlyPassedProxyTargetAccessor(targetInterfaces);
}

contributors = new List<ITypeContributor>
{
target,
additionalInterfacesContributor,
mixins,
instance
};
contributors = contributorsList;
return typeImplementerMapping.Keys;
}

Expand Down

0 comments on commit eae5dc3

Please sign in to comment.