From eae5dc3f6c5fa5f9468f0ac63bc4956bd967f4b5 Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Tue, 5 Jan 2021 14:28:02 +0100 Subject: [PATCH] Skip unnecessary contributors during proxy type generation (#552) 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`. --- .../Generators/BaseClassProxyGenerator.cs | 78 ++++++++++--------- .../Generators/BaseInterfaceProxyGenerator.cs | 63 ++++++++------- 2 files changed, 75 insertions(+), 66 deletions(-) diff --git a/src/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs index db25bcbbfa..638f32131e 100644 --- a/src/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/BaseClassProxyGenerator.cs @@ -100,21 +100,24 @@ protected sealed override Type GenerateType(string name, INamingScope namingScop private IEnumerable GetTypeImplementerMapping(out IEnumerable contributors, INamingScope namingScope) { - var methodsToSkip = new List(); - var proxyInstance = GetProxyInstanceContributor(methodsToSkip); - // TODO: the trick with methodsToSkip is not very nice... - var proxyTarget = GetProxyTargetContributor(methodsToSkip, namingScope); - IDictionary typeImplementerMapping = new Dictionary(); + var contributorsList = new List(capacity: 4); + var methodsToSkip = new List(); // TODO: the trick with methodsToSkip is not very nice... + var targetInterfaces = targetType.GetAllInterfaces(); + var typeImplementerMapping = new Dictionary(); // 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)) @@ -123,68 +126,69 @@ private IEnumerable GetTypeImplementerMapping(out IEnumerable 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 - { - proxyTarget, - mixins, - additionalInterfacesContributor, - proxyInstance - }; + contributors = contributorsList; return typeImplementerMapping.Keys; } diff --git a/src/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs b/src/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs index 772a109165..cab25c0207 100644 --- a/src/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs +++ b/src/Castle.Core/DynamicProxy/Generators/BaseInterfaceProxyGenerator.cs @@ -146,16 +146,21 @@ protected virtual IEnumerable GetTypeImplementerMapping(Type proxyTargetTy out IEnumerable contributors, INamingScope namingScope) { - IDictionary typeImplementerMapping = new Dictionary(); - var mixins = new MixinContributor(namingScope, AllowChangeTarget) { Logger = Logger }; + var contributorsList = new List(capacity: 4); + var targetInterfaces = proxyTargetType.GetAllInterfaces(); + var typeImplementerMapping = new Dictionary(); + // 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)) @@ -164,60 +169,60 @@ protected virtual IEnumerable GetTypeImplementerMapping(Type proxyTargetTy 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 - { - target, - additionalInterfacesContributor, - mixins, - instance - }; + contributors = contributorsList; return typeImplementerMapping.Keys; }