首页 > 解决方案 > 在选择构造函数时发现 Moq 库中的潜在错误

问题描述

我有以下设置并使用Moq版本 4.13.1。我不确定这是否是一个错误,但我想知道如何解决这个问题并将 null 传递给构造函数参数。

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

我收到以下错误:

未处理的异常。System.Reflection.AmbiguousMatchException:找到不明确的匹配项。

堆栈跟踪:

   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()

标签: c#.net-coremoq

解决方案


您的(A)null强制转换不起作用,因为构造函数重载Mock<T>需要 a params object[],因此您的所有参数最终都会成为对象。在这种情况下,预计会出现模棱两可的匹配。

但是,有一个构造函数重载,它需要一个Expression<Func<Foo>>

var fooMock = new Mock<Foo>(() => new Foo("Hello, World", (A)null, new Bar()));

这使您可以明确地选择要调用的构造函数。但是,这也会因同样的错误而失败,我认为这是一个错误,或者至少是一个错失的机会。提出一个问题可能是个好主意:此功能是在#888中引入的。

你可以做一个有点hacky的解决方法:

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());

现在只有一个构造函数(因为构造函数不是在 C# 中继承的),并且不再存在模棱两可的匹配。


推荐阅读