Reputation: 1578
I have the following setup and using Moq version 4.13.1. I am not sure this is a bug or not but I am wondering how can I get around this problem and pass null to the constructor argument.
public class Foo
{
public Foo() { Console.Write("Foo() called"); }
public Foo(string name, A _, Bar bar): this() { Console.Write("Foo(A) called"); }
public Foo(string name, B _, Bar bar): this() { Console.Write("Foo(B) called"); }
}
public class A { }
public class B { }
public class Bar { }
class Program
{
static void Main(string[] args)
{
// using default(A) will yield the same error
var fooMock = new Mock<Foo>("Hello world!", (A) null, new Bar());
var instance = fooMock.Object;
Console.WriteLine(instance);
}
}
I am getting the following error:
Unhandled exception. System.Reflection.AmbiguousMatchException: Ambiguous match found.
Stacktrace:
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)
at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
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 Moq.CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments)
at Moq.Mock`1.InitializeInstance()
at Moq.Mock`1.OnGetObject()
at Moq.Mock.get_Object()
at Moq.Mock`1.get_Object()
Upvotes: 0
Views: 355
Reputation: 42320
Your (A)null
casts won't work, because that constructor overload of Mock<T>
takes a params object[]
, so all of your parameters end up as objects anyway. An ambiguous match in this case is expected.
However, there is a constructor overload which takes an Expression<Func<Foo>>
:
var fooMock = new Mock<Foo>(() => new Foo("Hello, World", (A)null, new Bar()));
This lets you unambiguously choose the constructor to call. However, this also fails with the same error, and I would consider that a bug, or a least a missed opportunity. It would probably be a good idea to raise an issue: this feature was introduced in #888.
You can do a slightly hacky workaround:
public class MockFoo : Foo
{
public MockFoo(string name, A _, Bar bar) : base(name, _, bar) { }
}
var fooMock = new Mock<MockFoo>("Hello, World", (A)null, new Bar());
Now there's only one constructor (because constructors aren't inherited in C#), and there's no longer an ambiguous match.
Upvotes: 3