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

Trying to configure/override a generic overridden virtual method with an out parameter on a class substitute throws an exception #716

Open
rbeurskens opened this issue Jun 15, 2023 · 2 comments

Comments

@rbeurskens
Copy link

rbeurskens commented Jun 15, 2023

Describe the bug
Trying to configure/override a generic overridden virtual method with an out parameter on a class substitute throws an exception.

System.ArgumentException : Could not find method overriding Boolean TryCreateControl[TResult](IBaseControl, IHasGridLinesDefined, TResult ByRef) on type MyControlFactory. This is most likely a bug. Please report it.
   at Castle.DynamicProxy.Internal.InvocationHelper.ObtainMethod(MethodInfo proxiedMethod, Type type)
   at Castle.Core.Internal.SynchronizedDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Castle.DynamicProxy.Internal.InvocationHelper.GetMethodOnType(Type type, MethodInfo proxiedMethod)
   at NSubstitute.Proxies.CastleDynamicProxy.CastleInvocationMapper.Map(IInvocation castleInvocation)
   at NSubstitute.Proxies.CastleDynamicProxy.CastleForwardingInterceptor.Intercept(IInvocation invocation)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.MyControlFactoryProxy.TryCreateControl[TResult](IBaseControl control, IHasGridLinesDefined parentGrid, TResult& result)

To Reproduce

given:

public interface IControlFactory
{
    bool TryCreateControl<TResult>(IBaseControl control, IHasGridLinesDefined? parentGrid, [MaybeNullWhen(false)] out TResult result);
}
public class ControlFactory: IControlFactory
{
    public virtual bool TryCreateControl<TResult>(IBaseControl control, IHasGridLinesDefined? parentGrid, [MaybeNullWhen(false)] out TResult result) { /* ... */ }
}
public class MyControlFactory: ControlFactory
{
    // If this override is removed, code runs as expected
    public override bool TryCreateControl<TResult>(IBaseControl control, IHasGridLinesDefined? parentGrid, [MaybeNullWhen(false)] out TResult result) { /* ... */ }
}

[Test]
void MyTest()
{
    var control = Substitute.For<IStringTextBoxControl>();
    var controlFactory = Substitute.For<MyControlFactory>();
    controlFactory.Configure().TryCreateControl<object>(default, default, out var _)
          .ReturnsForAnyArgs(ci => { ci[2] = control; return true; }); // <== exception here
}

Expected behaviour
Runs normally and the method returns the desired object when called

Environment:

  • NSubstitute version: 5.0.0
  • NSubstitute.Analyzers version: CSharp 1.0.16
  • Platform: .NET Framework 4.8

Additional context
This might be a bug in Castle.Core or wrong usage of it, but I can't tell.
If the method override in the MyControlFactory class is removed, the exception does not occur and code runs as expected

@rbeurskens
Copy link
Author

See referenced issue in Caste.Core. I guess whenever they release a version that includes the fix, I can just use the updated Casle.Core version to resolve the problem.

@dtchepak
Copy link
Member

dtchepak commented Sep 3, 2023

Thanks @rbeurskens . Happy to bump the Castle.Core version when a fix is included. 👍

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

No branches or pull requests

2 participants