How to use DI when spawning new Windows Forms downstream?

帅比萌擦擦* 提交于 2019-12-22 08:57:17

问题


I have the Unity DI container working initially with my Windows Forms application. In Program.cs I have the following:

static void Main()
{
    var container = BuildUnityContainer();
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(container.Resolve<MainForm>());
}

private static IUnityContainer BuildUnityContainer()
{
    var container = new UnityContainer();
    container.RegisterType<ITest, MyTestClass>();
    container.RegisterType<ISomeOtherTest, MyOtherClass>();
    return container;
}

In my MainForm constructor I have the following which does work:

private readonly ITest test;

        public MainForm(ITest test)
        {
            this.test = test;
            InitializeComponent();
        }

The container is resolved and the code works fine. The problem / question is, how do I instantiate a new form from MainForm, say Form2 that has the following constructor:

private readonly ISomeOtherTest someOtherTest;

    public Form2(ISomeOtherTest someOtherTest)
    {
       this.someOtherTest = someOtherTest;
       InitializeComponent();
    }

If I try the following in my MainForm:

Form2 form2 = new Form2();
form2.Show();

It will break, complaining that I have not supplied the values to the constructor. However I have already resolved my container and I thought all downstream containers would be resolved. Obviously I'm missing something here though as it does not work.

Does this mean I have to front load all dependencies into MainForm even if that form does not use it so I can then pass them to any new form instantiations I make? The would be weird if I had 50 dependencies to resolve and had the constructor for the top level form take them all. Please help clear up my understanding as I have used Unity and DI containers almost exclusively in Web API and MVC which already has the DI resolver built in for the Controllers, so I must be missing some pieces and understanding here.


回答1:


You should create your form like so

Form2 form = container.Resolve<Form2>();

You were not using the container, therefore the Form does not have a constructor which takes no arguments. If you resolve it with the container, it will examine the constructor, find the dependencies and automatically inject them into the constructor for you.

So.. maybe your problem is that you do not have access to the container in your MainForm? If this is the problem there are two approaches..

Inject IUnityContainer into MainForm constructor

However... people who live by the "composition root" pattern will tell you that you should only use the container from the root of your application (in this case, probably Main() ) The other option is...

Create a Form2 factory class from your composition root (Main) which gets injected into MainForm and MainForm uses the factory to create Form2

You should read more into the Composition Root theory of thinking...

Composition Root


update

I've never had to do it before, but I think the second method would look something like this...

public class Form2Factory : IForm2Factory
{
    private readonly ISomeOtherTest someOtherTest;

    public Form2Factory(ISomeOtherTest someOtherTest)
    {
        this.someOtherTest = someOtherTest;
    }

    public Form2 Create()
    {
        return new Form2(someOtherTest);
    }
}


public class MainForm
{
    private readonly IForm2Factory form2Factory;

    public MainForm(IForm2Factory form2Factory)
    {
        this.form2Factory = form2Factory;
    }

    private void DoingSomething()
    {
        Form2 form = form2Factory.Create();
        form.Show();
    }
}


来源:https://stackoverflow.com/questions/17436334/how-to-use-di-when-spawning-new-windows-forms-downstream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!