选择构造函数时发现 Moq 库中存在潜在错误
Found a potential bug in Moq library while selecting a constructor
我有以下设置并使用 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);
}
}
我收到以下错误:
Unhandled 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)
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()
您的 (A)null
转换将不起作用,因为 Mock<T>
的构造函数重载需要一个 params object[]
,所以您的所有参数无论如何最终都会成为对象。预计在这种情况下会出现不明确的匹配。
但是,有一个构造函数重载需要 Expression<Func<Foo>>
:
var fooMock = new Mock<Foo>(() => new Foo("Hello, World", (A)null, new Bar()));
这使您可以明确选择要调用的构造函数。 但是,这也失败并出现同样的错误,我认为这是一个错误,或者至少是错失的机会。 raise an issue: this feature was introduced in #888.
可能是个好主意
你可以做一个稍微复杂的解决方法:
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# 中不继承构造函数),并且不再有歧义匹配。
我有以下设置并使用 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);
}
}
我收到以下错误:
Unhandled 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)
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()
您的 (A)null
转换将不起作用,因为 Mock<T>
的构造函数重载需要一个 params object[]
,所以您的所有参数无论如何最终都会成为对象。预计在这种情况下会出现不明确的匹配。
但是,有一个构造函数重载需要 Expression<Func<Foo>>
:
var fooMock = new Mock<Foo>(() => new Foo("Hello, World", (A)null, new Bar()));
这使您可以明确选择要调用的构造函数。 但是,这也失败并出现同样的错误,我认为这是一个错误,或者至少是错失的机会。 raise an issue: this feature was introduced in #888.
可能是个好主意你可以做一个稍微复杂的解决方法:
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# 中不继承构造函数),并且不再有歧义匹配。