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

Convert AttributesToAvoidReplicating to a ProxyGenerationOptions property #575

Closed
Closed
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Enhancements:
- .NET Standard 2.0 and 2.1 support (@lg2de, #485)
- Non-intercepted methods on a class proxy with target are now forwarded to the target (@stakx, #571)
- Significant performance improvements with proxy type generation for interface proxies without target. (Up until now, DynamicProxy generated a separate `IInvocation` implementation type for every single proxied method – it is now able to reuse a single predefined type in many cases, thereby reducing the total amount of dynamic type generation.) (@stakx, #573)
- `AttributesToAvoidReplicating` has been converted from a static class to a collection property on `ProxyGenerationOptions` (@stakx, #575)

Bugfixes:
- Proxying certain `[Serializable]` classes produces proxy types that fail PEVerify test (@stakx, #367)
Expand Down
10 changes: 1 addition & 9 deletions ref/Castle.Core-net45.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2653,6 +2653,7 @@ public class ProxyGenerationOptions : System.Runtime.Serialization.ISerializable
public ProxyGenerationOptions() { }
public ProxyGenerationOptions(Castle.DynamicProxy.IProxyGenerationHook hook) { }
public System.Collections.Generic.IList<Castle.DynamicProxy.CustomAttributeInfo> AdditionalAttributes { get; }
public System.Collections.Generic.ISet<System.Type> AttributesToAvoidReplicating { get; }
public System.Type BaseTypeForInterfaceProxy { get; set; }
public bool HasMixins { get; }
public Castle.DynamicProxy.IProxyGenerationHook Hook { get; set; }
Expand Down Expand Up @@ -2758,15 +2759,6 @@ protected virtual void PostProceed(Castle.DynamicProxy.IInvocation invocation) {
protected virtual void PreProceed(Castle.DynamicProxy.IInvocation invocation) { }
}
}
namespace Castle.DynamicProxy.Generators
{
public static class AttributesToAvoidReplicating
{
public static void Add(System.Type attribute) { }
public static void Add<T>() { }
public static bool Contains(System.Type attribute) { }
}
}
namespace Castle.DynamicProxy.Internal
{
public abstract class CompositionInvocation : Castle.DynamicProxy.AbstractInvocation
Expand Down
10 changes: 1 addition & 9 deletions ref/Castle.Core-netstandard2.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2608,6 +2608,7 @@ public class ProxyGenerationOptions
public ProxyGenerationOptions() { }
public ProxyGenerationOptions(Castle.DynamicProxy.IProxyGenerationHook hook) { }
public System.Collections.Generic.IList<Castle.DynamicProxy.CustomAttributeInfo> AdditionalAttributes { get; }
public System.Collections.Generic.ISet<System.Type> AttributesToAvoidReplicating { get; }
public System.Type BaseTypeForInterfaceProxy { get; set; }
public bool HasMixins { get; }
public Castle.DynamicProxy.IProxyGenerationHook Hook { get; set; }
Expand Down Expand Up @@ -2711,15 +2712,6 @@ protected virtual void PostProceed(Castle.DynamicProxy.IInvocation invocation) {
protected virtual void PreProceed(Castle.DynamicProxy.IInvocation invocation) { }
}
}
namespace Castle.DynamicProxy.Generators
{
public static class AttributesToAvoidReplicating
{
public static void Add(System.Type attribute) { }
public static void Add<T>() { }
public static bool Contains(System.Type attribute) { }
}
}
namespace Castle.DynamicProxy.Internal
{
public abstract class CompositionInvocation : Castle.DynamicProxy.AbstractInvocation
Expand Down
10 changes: 1 addition & 9 deletions ref/Castle.Core-netstandard2.1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2608,6 +2608,7 @@ public class ProxyGenerationOptions
public ProxyGenerationOptions() { }
public ProxyGenerationOptions(Castle.DynamicProxy.IProxyGenerationHook hook) { }
public System.Collections.Generic.IList<Castle.DynamicProxy.CustomAttributeInfo> AdditionalAttributes { get; }
public System.Collections.Generic.ISet<System.Type> AttributesToAvoidReplicating { get; }
public System.Type BaseTypeForInterfaceProxy { get; set; }
public bool HasMixins { get; }
public Castle.DynamicProxy.IProxyGenerationHook Hook { get; set; }
Expand Down Expand Up @@ -2711,15 +2712,6 @@ protected virtual void PostProceed(Castle.DynamicProxy.IInvocation invocation) {
protected virtual void PreProceed(Castle.DynamicProxy.IInvocation invocation) { }
}
}
namespace Castle.DynamicProxy.Generators
{
public static class AttributesToAvoidReplicating
{
public static void Add(System.Type attribute) { }
public static void Add<T>() { }
public static bool Contains(System.Type attribute) { }
}
}
namespace Castle.DynamicProxy.Internal
{
public abstract class CompositionInvocation : Castle.DynamicProxy.AbstractInvocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ namespace Castle.DynamicProxy.Tests
using System.Reflection;
using System.Security.Permissions;

using Castle.DynamicProxy.Generators;
using Castle.DynamicProxy.Tests.Classes;

using NUnit.Framework;
Expand All @@ -28,26 +27,19 @@ namespace Castle.DynamicProxy.Tests
public class AttributesToAvoidReplicatingTestCase : BasePEVerifyTestCase
{
[Test]
public void After_adding_attribute_must_be_listed_as_contained()
{
AttributesToAvoidReplicating.Add<string>();
bool contains = AttributesToAvoidReplicating.Contains(typeof(string));
Assert.IsTrue(contains);
}

[Test]
public void After_adding_attribute_must_still_contain_original_attributes()
public void NonInheritableAttribute_should_be_replicated_as_it_is_not_inherited()
{
AttributesToAvoidReplicating.Add<string>();
bool contains = AttributesToAvoidReplicating.Contains(typeof(System.Runtime.InteropServices.ComImportAttribute));
Assert.IsTrue(contains);
var proxy = generator.CreateClassProxy<AttributedClass_NonInheritable>();
Assert.AreEqual(1, AttributeCount<NonInheritableAttribute>(proxy));
}

[Test]
public void NonInheritableAttribute_should_be_replicated_as_it_is_not_inherited()
public void NonInheritableAttribute_can_be_suppressed_via_AttributesToAvoidReplicating()
{
var proxy = generator.CreateClassProxy<AttributedClass_NonInheritable>();
Assert.AreEqual(1, AttributeCount<NonInheritableAttribute>(proxy));
var options = new ProxyGenerationOptions();
options.AttributesToAvoidReplicating.Add(typeof(NonInheritableAttribute));
var proxy = generator.CreateClassProxy<AttributedClass_NonInheritable>(options);
Assert.AreEqual(0, AttributeCount<NonInheritableAttribute>(proxy));
}

[NonInheritable]
Expand Down
41 changes: 27 additions & 14 deletions src/Castle.Core.Tests/DynamicProxy.Tests/ClassEmitterTestCase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,17 @@ public class ClassEmitterTestCase : BasePEVerifyTestCase
[Test]
public void AutomaticDefaultConstructorGeneration()
{
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "Foo", typeof (object), Type.EmptyTypes);
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "Foo", typeof (object), Type.EmptyTypes);
Type t = emitter.BuildType();
Activator.CreateInstance(t);
}

[Test]
public void AutomaticDefaultConstructorGenerationWithClosedGenericType()
{
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "Foo", typeof (List<object>),
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "Foo", typeof (List<object>),
Type.EmptyTypes);
Type t = emitter.BuildType();
Activator.CreateInstance(t);
Expand All @@ -44,7 +46,8 @@ public void AutomaticDefaultConstructorGenerationWithClosedGenericType()
[Test]
public void StaticMethodArguments()
{
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "Foo", typeof (List<object>),
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "Foo", typeof (List<object>),
Type.EmptyTypes);
MethodEmitter methodEmitter = emitter.CreateMethod("StaticMethod", MethodAttributes.Public | MethodAttributes.Static,
typeof (string), typeof (string));
Expand All @@ -56,7 +59,8 @@ public void StaticMethodArguments()
[Test]
public void InstanceMethodArguments()
{
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "Foo", typeof (List<object>),
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "Foo", typeof (List<object>),
Type.EmptyTypes);
MethodEmitter methodEmitter = emitter.CreateMethod("InstanceMethod", MethodAttributes.Public,
typeof (string), typeof (string));
Expand All @@ -70,7 +74,8 @@ public void InstanceMethodArguments()
public void ForceUnsignedFalseWithSignedTypes()
{
const bool shouldBeSigned = true;
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "Foo", typeof (object), Type.EmptyTypes,
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "Foo", typeof (object), Type.EmptyTypes,
TypeAttributes.Public, false);
Type t = emitter.BuildType();
Assert.AreEqual(shouldBeSigned, StrongNameUtil.IsAssemblySigned(t.Assembly));
Expand All @@ -79,7 +84,8 @@ public void ForceUnsignedFalseWithSignedTypes()
[Test]
public void ForceUnsignedTrueWithSignedTypes()
{
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "Foo", typeof (object), Type.EmptyTypes,
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "Foo", typeof (object), Type.EmptyTypes,
TypeAttributes.Public, true);
Type t = emitter.BuildType();
Assert.IsFalse(StrongNameUtil.IsAssemblySigned(t.Assembly));
Expand All @@ -88,7 +94,8 @@ public void ForceUnsignedTrueWithSignedTypes()
[Test]
public void CreateFieldWithAttributes()
{
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "Foo", typeof (object), Type.EmptyTypes);
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "Foo", typeof (object), Type.EmptyTypes);
emitter.CreateField("myField", typeof (string), FieldAttributes.FamANDAssem | FieldAttributes.InitOnly);
Type t = emitter.BuildType();
FieldInfo field = t.GetField("myField", BindingFlags.NonPublic | BindingFlags.Instance);
Expand All @@ -99,7 +106,8 @@ public void CreateFieldWithAttributes()
[Test]
public void CreateStaticFieldWithAttributes()
{
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "Foo", typeof (object), Type.EmptyTypes);
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "Foo", typeof (object), Type.EmptyTypes);
emitter.CreateStaticField("myField", typeof (string), FieldAttributes.FamANDAssem | FieldAttributes.InitOnly);
Type t = emitter.BuildType();
FieldInfo field = t.GetField("myField", BindingFlags.NonPublic | BindingFlags.Static);
Expand All @@ -110,7 +118,8 @@ public void CreateStaticFieldWithAttributes()
[Test]
public void UsingClassEmitterForInterfaces()
{
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "IFoo", null, Type.EmptyTypes,
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "IFoo", null, Type.EmptyTypes,
TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.Public, false);
emitter.CreateMethod("MyMethod", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual,
typeof(void), Type.EmptyTypes);
Expand All @@ -124,7 +133,8 @@ public void UsingClassEmitterForInterfaces()
public void NoBaseTypeForInterfaces()
{
DisableVerification();
ClassEmitter emitter = new ClassEmitter (generator.ProxyBuilder.ModuleScope, "IFoo", null, Type.EmptyTypes,
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "IFoo", null, Type.EmptyTypes,
TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.Public, false);

Assert.Throws<InvalidOperationException>(delegate {
Expand All @@ -138,7 +148,8 @@ public void NoBaseTypeForInterfaces()
public void NoDefaultCtorForInterfaces()
{
DisableVerification();
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "IFoo", null, Type.EmptyTypes,
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "IFoo", null, Type.EmptyTypes,
TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.Public, false);

Assert.Throws<InvalidOperationException>(delegate {
Expand All @@ -150,7 +161,8 @@ public void NoDefaultCtorForInterfaces()
public void NoCustomCtorForInterfaces()
{
DisableVerification();
ClassEmitter emitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "IFoo", null, Type.EmptyTypes,
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter emitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "IFoo", null, Type.EmptyTypes,
TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.Public, false);

Assert.Throws<InvalidOperationException>(delegate {
Expand All @@ -161,9 +173,10 @@ public void NoCustomCtorForInterfaces()
[Test]
public void NestedInterface()
{
ClassEmitter outerEmitter = new ClassEmitter(generator.ProxyBuilder.ModuleScope, "IOuter", null, Type.EmptyTypes,
var context = new ProxyGenerationContext(ProxyGenerationOptions.Default);
ClassEmitter outerEmitter = new ClassEmitter(context, generator.ProxyBuilder.ModuleScope, "IOuter", null, Type.EmptyTypes,
TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.Public, false);
NestedClassEmitter innerEmitter = new NestedClassEmitter(outerEmitter, "IInner",
NestedClassEmitter innerEmitter = new NestedClassEmitter(context, outerEmitter, "IInner",
TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.NestedPublic, null, Type.EmptyTypes);
innerEmitter.CreateMethod("MyMethod", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual,
typeof(void), Type.EmptyTypes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ namespace Castle.DynamicProxy.Contributors

internal class ClassMembersCollector : MembersCollector
{
public ClassMembersCollector(Type targetType)
: base(targetType)
public ClassMembersCollector(ProxyGenerationContext context, Type targetType)
: base(context, targetType)
{
}

protected override MetaMethod GetMethodToGenerate(MethodInfo method, IProxyGenerationHook hook, bool isStandalone)
protected override MetaMethod GetMethodToGenerate(MethodInfo method, bool isStandalone)
{
if (ProxyUtil.IsAccessibleMethod(method) == false)
{
return null;
}

var accepted = AcceptMethod(method, true, hook);
var accepted = AcceptMethod(method, true);
if (!accepted && !method.IsAbstract)
{
//we don't need to do anything...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public ClassProxySerializableContributor(Type targetType, Type[] interfaces, str
Debug.Assert(targetType.IsSerializable, "This contributor is intended for serializable types only.");
}

public override void CollectElementsToProxy(IProxyGenerationHook hook, MetaType model)
public override void CollectElementsToProxy(MetaType model)
{
delegateToBaseGetObjectData = VerifyIfBaseImplementsGetObjectData(targetType, model, out var getObjectData);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ internal class ClassProxyTargetContributor : CompositeTypeContributor
{
private readonly Type targetType;

public ClassProxyTargetContributor(Type targetType, INamingScope namingScope)
: base(namingScope)
public ClassProxyTargetContributor(ProxyGenerationContext context, INamingScope namingScope,
Type targetType)
: base(context, namingScope)
{
this.targetType = targetType;
}

protected override IEnumerable<MembersCollector> GetCollectors()
{
var targetItem = new ClassMembersCollector(targetType) { Logger = Logger };
var targetItem = new ClassMembersCollector(Context, targetType);
yield return targetItem;

foreach (var @interface in interfaces)
{
var item = new InterfaceMembersOnClassCollector(@interface, true,
targetType.GetInterfaceMap(@interface)) { Logger = Logger };
var item = new InterfaceMembersOnClassCollector(Context, @interface, true, targetType.GetInterfaceMap(@interface));
yield return item;
}
}
Expand Down Expand Up @@ -87,16 +87,12 @@ private Type BuildInvocationType(MetaMethod method, ClassEmitter @class)
var methodInfo = method.Method;
if (!method.HasTarget)
{
return new InheritanceInvocationTypeGenerator(targetType,
method,
null, null)
return new InheritanceInvocationTypeGenerator(Context, targetType, method, null, null)
.Generate(@class, namingScope)
.BuildType();
}
var callback = CreateCallbackMethod(@class, methodInfo, method.MethodOnTarget);
return new InheritanceInvocationTypeGenerator(callback.DeclaringType,
method,
callback, null)
return new InheritanceInvocationTypeGenerator(Context, callback.DeclaringType, method, callback, null)
.Generate(@class, namingScope)
.BuildType();
}
Expand Down Expand Up @@ -132,7 +128,7 @@ private MethodGenerator ExplicitlyImplementedInterfaceMethodGenerator(MetaMethod
{
var @delegate = GetDelegateType(method, @class);
var contributor = GetContributor(@delegate, method);
var invocation = new InheritanceInvocationTypeGenerator(targetType, method, null, contributor)
var invocation = new InheritanceInvocationTypeGenerator(Context, targetType, method, null, contributor)
.Generate(@class, namingScope)
.BuildType();
return new MethodWithInvocationGenerator(method,
Expand Down Expand Up @@ -166,7 +162,7 @@ private Type GetDelegateType(MetaMethod method, ClassEmitter @class)
null);

return scope.TypeCache.GetOrAddWithoutTakingLock(key, _ =>
new DelegateTypeGenerator(method, targetType)
new DelegateTypeGenerator(Context, method, targetType)
.Generate(@class, namingScope)
.BuildType());
}
Expand Down
Loading