Обнаружена потенциальная ошибка в библиотеке Moq при выборе конструктора - PullRequest
1 голос
/ 07 февраля 2020

У меня есть следующие настройки и использую 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: найдено неоднозначное совпадение.

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

1 Ответ

2 голосов
/ 07 февраля 2020

Ваши (A)null приведения не будут работать, потому что эта перегрузка конструктора Mock<T> принимает params object[], поэтому все ваши параметры в конечном итоге становятся объектами. В этом случае ожидается неоднозначное совпадение.

Однако имеется перегрузка конструктора, которая принимает Expression<Func<Foo>>:

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

Это позволяет однозначно выбрать конструктор для вызова. Однако , это также не с той же ошибкой, и я считаю, что это ошибка или, по крайней мере, упущенная возможность. Вероятно, было бы неплохо поднять проблему : эта функция была введена в # 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#), и больше нет неоднозначного соответствия.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...