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

Optional arguments in constructor #165

Closed
candychiu opened this issue Oct 23, 2014 · 3 comments
Closed

Optional arguments in constructor #165

candychiu opened this issue Oct 23, 2014 · 3 comments

Comments

@candychiu
Copy link

I can't seem to create sub's when the constructor contains optional arguments.

[Test]
public void Test()
{
var a = Substitute.For(1);
}

////// scenario 1: default constructor not explicitly defined
public class A {
internal A(int arg1 = 0, string arg2 = "") {}
}
Result Message: System.NotSupportedException : Parent does not have a default constructor. The default constructor must be explicitly defined.
Result StackTrace:
at System.Reflection.Emit.TypeBuilder.DefineDefaultConstructorNoLock(MethodAttributes attributes)
at System.Reflection.Emit.TypeBuilder.DefineDefaultConstructor(MethodAttributes attributes)
at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
at System.Reflection.Emit.TypeBuilder.CreateType()
at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.CreateType(TypeBuilder type)
at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateType(String name, Type[] interfaces, INamingScope namingScope)
at Castle.DynamicProxy.Generators.ClassProxyGenerator.<>c__DisplayClass1.b__0(String n, INamingScope s)
at Castle.DynamicProxy.Generators.BaseProxyGenerator.ObtainProxyType(CacheKey cacheKey, Func`3 factory)
at Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode(Type[] interfaces, ProxyGenerationOptions options)
at Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.CreateProxyUsingCastleProxyGenerator(Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments, IInterceptor interceptor, ProxyGenerationOptions proxyGenerationOptions)
at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments)
at NSubstitute.Proxies.ProxyFactory.GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments)
at NSubstitute.Core.SubstituteFactory.Create(Type[] typesToProxy, Object[] constructorArguments, SubstituteConfig config)
at NSubstitute.Core.SubstituteFactory.Create(Type[] typesToProxy, Object[] constructorArguments)
at NSubstitute.Substitute.For(Type[] typesToProxy, Object[] constructorArguments)
at NSubstitute.Substitute.For[T](Object[] constructorArguments)

////// scenario 2: default constructor explicitly defined
public class A {
internal A() {}
internal A(int arg1 = 0, string arg2 = "") {}
}
Result Message:
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: Testing.NSubOptionalArg+A.
Could not find a constructor that would match given arguments:
System.Int32
Result StackTrace:
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments)
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.CreateProxyUsingCastleProxyGenerator(Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments, IInterceptor interceptor, ProxyGenerationOptions proxyGenerationOptions)
at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments)
at NSubstitute.Proxies.ProxyFactory.GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments)
at NSubstitute.Core.SubstituteFactory.Create(Type[] typesToProxy, Object[] constructorArguments, SubstituteConfig config)
at NSubstitute.Core.SubstituteFactory.Create(Type[] typesToProxy, Object[] constructorArguments)
at NSubstitute.Substitute.For(Type[] typesToProxy, Object[] constructorArguments)
at NSubstitute.Substitute.For[T](Object[] constructorArguments)

@dtchepak
Copy link
Member

Hi @candychiu,
It seems to work ok with public constructors if the arguments are explicitly passed or if there is a default, public constructor. It does not work with default args, I think because the compiler doesn't know to insert them in this case?

        public class A { public A(int arg1 = 0, string arg2 = "") { } }
        [Test]
        public void Sample() { var a = Substitute.For<A>(0, ""); }

If you have to keep the constructors internal, maybe try using InternalsVisibleTo?

@candychiu
Copy link
Author

That works, thanks. Is this a limitation of the compiler or dynamic proxy library?

@dtchepak
Copy link
Member

I'm not sure on the details sorry. There's an explanation of the internal thing on SO. My very rudimentary (read: probably wrong) knowledge of optional args in C# is that default values are inserted at compile time. If we are dynamically calling a constructor then those argument values will not have been compiled in with that call, so we need to pass them explicitly.

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