Skip to content

Commit

Permalink
Merge pull request #556 from stakx/private-protected-methods
Browse files Browse the repository at this point in the history
Fix interception for `private protected` methods
  • Loading branch information
stakx committed Jan 19, 2021
2 parents 9377ba4 + b1baa73 commit 0075029
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -6,6 +6,7 @@ Enhancements:
- .NET Standard 2.0 and 2.1 support (@lg2de, #485)

Bugfixes:
- `private protected` methods are not intercepted (@CrispyDrone, #535)
- `System.UIntPtr` unsupported (@stakx, #546)

Deprecations:
Expand Down
46 changes: 46 additions & 0 deletions src/Castle.Core.Tests/DynamicProxy.Tests/AccessLevelTestCase.cs
Expand Up @@ -14,6 +14,7 @@

namespace Castle.DynamicProxy.Tests
{
using System;
using System.Collections.Generic;
using System.Reflection;

Expand Down Expand Up @@ -85,5 +86,50 @@ public void InternalConstructorIsReplicatedWhenInternalsVisibleTo()
object proxy = generator.CreateClassProxy(typeof(InternalClass), new StandardInterceptor());
Assert.IsNotNull(proxy.GetType().GetConstructor(new[] { typeof(IInterceptor[]) }));
}

[TestCase(typeof(InternalMethodClass))]
[TestCase(typeof(PrivateProtectedMethodClass))]
[TestCase(typeof(ProtectedMethodClass))]
[TestCase(typeof(ProtectedInternalMethodClass))]
public void Methods_made_visible_by_InternalsVisibleTo_can_be_intercepted(Type methodClass)
{
var method = methodClass.GetMethod("Method", BindingFlags.NonPublic | BindingFlags.Instance);
Assume.That(ProxyUtil.IsAccessible(method)); // because this assembly makes its internals visible to DynamicProxy

var realObj = (IMethodClass)Activator.CreateInstance(methodClass);
Assert.Throws<Exception>(realObj.InvokeMethod);

var proxy = (IMethodClass)generator.CreateClassProxy(methodClass, new DoNothingInterceptor());
Assert.DoesNotThrow(proxy.InvokeMethod);
}

private interface IMethodClass
{
void InvokeMethod();
}

public class InternalMethodClass : IMethodClass
{
public void InvokeMethod() => Method();
internal virtual void Method() => throw new Exception();
}

public class PrivateProtectedMethodClass : IMethodClass
{
public void InvokeMethod() => Method();
private protected virtual void Method() => throw new Exception();
}

public class ProtectedMethodClass : IMethodClass
{
public void InvokeMethod() => Method();
protected virtual void Method() => throw new Exception();
}

public class ProtectedInternalMethodClass : IMethodClass
{
public void InvokeMethod() => Method();
protected internal virtual void Method() => throw new Exception();
}
}
}
Expand Up @@ -223,7 +223,7 @@ protected bool AcceptMethod(MethodInfo method, bool onlyVirtuals, IProxyGenerati
}

//can only proxy methods that are public or protected (or internals that have already been checked above)
if ((method.IsPublic || method.IsFamily || method.IsAssembly || method.IsFamilyOrAssembly) == false)
if ((method.IsPublic || method.IsFamily || method.IsAssembly || method.IsFamilyOrAssembly || method.IsFamilyAndAssembly) == false)
{
return false;
}
Expand Down

0 comments on commit 0075029

Please sign in to comment.