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

invocation.MethodInvocationTarget throws ArgumentNullException for default interface method #684

Open
stakx opened this issue Aug 30, 2024 · 1 comment
Labels
Milestone

Comments

@stakx
Copy link
Member

stakx commented Aug 30, 2024

Repro code

var generator = new ProxyGenerator();
var foo = generator.CreateInterfaceProxyWithoutTarget<IFoo>(new InspectInvocation());
foo.Bar();

public interface IFoo
{
    void Bar() { }
}

public class InspectInvocation : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Debug.Assert(invocation.InvocationTarget == null || invocation.MethodInvocationTarget != null);  // will throw
    }
}

Expected outcome

Unless I misunderstand the meaning of IInvocation.InvocationTarget and IInvocation.MethodInvocationTarget, I would expect the latter to point to a method of the former's type, if the former (IInvocation.InvocationTarget) is non-null.

Actual outcome

MethodInvocationTarget will throw an ArgumentNullException due to the invocation's targetType not being set.

Affected version(s)

Castle.Core starting at tag v5.2.0

/cc @dtchepak @zvirja @alexandrnikitin – this will likely matter for NSubstitute (in https://github.com/nsubstitute/NSubstitute/blob/4d258a28aba054ea18785d36b4bdd83da023aefb/src/NSubstitute/Proxies/CastleDynamicProxy/CastleInvocationMapper.cs#L11-L16) once we've published version 5.2.0 and you upgrade to that version.

@stakx stakx added the bug label Aug 30, 2024
@stakx stakx added this to the vNext milestone Aug 30, 2024
@stakx
Copy link
Member Author

stakx commented Aug 30, 2024

If I understand things correctly, then generally speaking the "target" is whatever one can .Proceed() to:

  • For composition-based proxies, a target object can be supplied explicitly.
  • For inheritance-based proxies, the target can be either missing (i. e. null) or the intercepted method's implementation inherited from the proxied type.

If the above assumptions are correct, then for an IInvocation representing an intercepted default interface method...:

  • invocation.TargetType should return the interface type where the default implementation resides.
  • invocation.InvocationTarget should return the same as invocation.Proxy.
  • invocation.MethodInvocationTarget should return the MethodInfo of the method with the default implementation... so possibly the same as invocation.Method?

@jonorossi, sorry to bother you again, but are my assumptions and conclusions correct, or am I missing some finer distinctions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant