Skip to content

CreateClassProxy: Unable to specify ctor to use when passing ambiguous ctor args #480

@stakx

Description

@stakx

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:

[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);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions