-
Notifications
You must be signed in to change notification settings - Fork 484
Description
Somewhat of an edge case perhaps, but we just got a bug report over at Moq that essentially boils down to this:
using Castle.DynamicProxy;
public class Foo
{
public Foo(A a) { }
public Foo(B b) { }
}
public class A { }
public class B { }
var generator = new ProxyGenerator();
var proxy = (Foo)generator.CreateClassProxy(typeof(Foo), new object[] { default(A) }, new StandardInterceptor());which throws the following exception:
System.Reflection.AmbiguousMatchException: Ambiguous match found.
at System.DefaultBinder.BindToMethod(BindingFlags bindingAttr, MethodBase[] match, Object[]& args, ParameterModifier[] modifiers, CultureInfo cultureInfo, String[] names, Object& state)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Activator.CreateInstance(Type type, Object[] args)
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 Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Object[] constructorArguments, IInterceptor[] interceptors)
at Program.Main()
The reason is quite clear, the ctor argument default(A) is equivalent to null, and that null is being put in a object[] array, so all type information is lost and it's impossible for Reflection to decide whether Foo..ctor(A) or Foo..ctor(B) was intended to be called.
The only way around this problem would be to enhance DynamicProxy's API such that either (a) the targeted base ctor could be specified in the form of a ConstructorInfo; or (b) the ctor argument types could get passed in a separate Type[].
P.S. just discovered an old (disabled) test for this:
Core/src/Castle.Core.Tests/DynamicProxy.Tests/ClassProxyConstructorsTestCase.cs
Lines 156 to 164 in 6a81dd5
| [Test] | |
| [Ignore("I don't see any simple way of doing this...")] | |
| public void Should_properly_interpret_null_as_ctor_argument() | |
| { | |
| var proxy = | |
| (ClassWithVariousConstructors) | |
| generator.CreateClassProxy(typeof(ClassWithVariousConstructors), new[] { default(object) }); | |
| Assert.AreEqual(Constructor.Object, proxy.ConstructorCalled); | |
| } |