У меня есть IFormFactory
в моем проекте Windows Forms с параметризованными методами, которые возвращают конкретные Form
подклассы. Раньше я использовал Ninject.Extensions.Factory
Bind<IFormFactory>().ToFactory()
для привязки фабрики к динамически сгенерированной прокси-реализации. (При вызове метода в интерфейсе Ninject автоматически вызывает конструктор с наиболее подходящими аргументами.)
Я пытаюсь повторить эту настройку в DryIoc, но у меня возникают проблемы с передачей аргументов вконструктор форм. DryIoc обрабатывает аргументы Resolve(args)
как «замещающие» зависимости, но я хочу строго использовать эти аргументы как «немые» аргументы конструктора. Пример:
public interface IFormFactory
{
MyForm MyForm(string word, int number);
MyForm MyForm(string word, int number, bool flag);
}
public class FormFactory : IFormFactory
{
private readonly IResolver m_resolver;
private readonly MethodInfo m_method1;
private readonly MethodInfo m_method2;
public FormFactory(IContainer container)
{
m_resolver = container;
// I reflect over the methods on IFormFactory
m_method1 = typeof(IFormFactory).GetMethod(nameof(IFormFactory.MyForm), new Type[] { typeof(string), typeof(int) });
m_method2 = typeof(IFormFactory).GetMethod(nameof(IFormFactory.MyForm), new Type[] { typeof(string), typeof(int), typeof(bool) });
// I do this dynamically, by counting parameters
var constructor1 = m_method1.ReturnType.GetConstructor(new Type[] { typeof(IService), typeof(string), typeof(int) });
var constructor2 = m_method2.ReturnType.GetConstructor(new Type[] { typeof(IService), typeof(string), typeof(int), typeof(bool) });
// make a registration for each method that calls the selected constructor
container.Register(
m_method1.ReturnType,
made: Made.Of(FactoryMethod.Of(constructor1)),
serviceKey: m_method1);
container.Register(
m_method2.ReturnType,
made: Made.Of(FactoryMethod.Of(constructor2)),
serviceKey: m_method2);
}
public MyForm MyForm(string word, int number)
{
return (MyForm)m_resolver.Resolve(m_method1.ReturnType, new object[] { word, number }, serviceKey: m_method1);
}
public MyForm MyForm(string word, int number, bool flag)
{
return (MyForm)m_resolver.Resolve(m_method2.ReturnType, new object[] { word, number, flag }, serviceKey: m_method2);
}
}
public interface IService { }
public class ServiceImpl : IService { }
public class MyForm
{
public MyForm(IService service, string word, int number) { Console.WriteLine("constructor1"); }
public MyForm(IService service, string word, int number, bool flag) { Console.WriteLine("constructor2"); }
}
void Main()
{
using (var container = new Container())
{
container.Register<IService, ServiceImpl>();
container.Register<IFormFactory, FormFactory>(reuse: Reuse.Singleton);
var factory = container.Resolve<IFormFactory>();
// this works because DryIoc uses these parameters as "dependencies" for the constructor
factory.MyForm("word", 1);
// this throws
factory.MyForm(null, 2, true);
}
}
Передача null
любому из аргументов throws, потому что DryIoc хочет предоставить «зависимость».
ContainerException: Unable to resolve String as parameter "word" with passed arguments [null]
in MyForm {ServiceKey=MyForm MyForm(System.String, Int32, Boolean)} FactoryId=46 with passed arguments [null] IsResolutionCall
from Container without Scope
Where no service registrations found
and no dynamic registrations found in 0 of Rules.DynamicServiceProviders
and nothing found in 0 of Rules.UnknownServiceResolvers
Я думал о вызове конструктора и разрешении каждой зависимостив явном виде, но, похоже, это имеет много недостатков для контекстных привязок, повторного использования и т. д.
public MyForm MyForm(string word, int number, bool flag)
{
return new MyForm(
m_resolver.Resolve<IService>(),
word,
number,
flag);
}
Возможно ли создать регистрацию, которая будет передавать args
в качестве глупых аргументов, а не обрабатывать их как зависимости