I recently worked a bit with IOC containers (LightInject in my case).
I read that you only need to use the ONCE container, at startup, and not somewhere else. This is what I am trying to understand. If I can only reference the container in the bootstrap / startup method, how can I resolve what I need, elswhere in the project or at runtime, if the class depends on user input.
So, in my traditional Windows Forms application, on form loading, let's say I would load LightInject according to the code below. This is only an arbitrary example, it is rather a prerequisite in which I need to get my head.
I might miss something here or just not get it. But how should I resolve dependencies, If I cannot use / should not reference or use Container.GetInstance / Resolve / {Select the IOC syntax here} and only in the root of the composition.
For an instance, let's say I have two buttons and a text box in my form. The first button gets me an ILoader (below code), and the second button loads a file viewer (ILoader, below code), whose file name is what is entered in the text field on winform.
Without an IOC container, I would do the following (just suppose it is placed in a click event)
Button 1 Press "Event":
ISplitText MyStringFunc = new WhateverImplementsIt();
Button 2 (receives a file reader based on text field input)
ILoader MyLoader = new FileReaderImplementation(TextBox1.Text);
Using LightInject, I am definitely forced to do the following:
Button1 Click:
ISplitText Splitter = Container.GetInstance<ISplitText>();
Button 2 Press
var LoaderFunc = Container.GetInstance<Func<string, ILoader>>();
ILoader l2 = LoaderFunc(TextBox1.Text);
? Container.GetInstance, , , , 1 , , ?
. :
Container = new Container();
Container.Register<IFoo,Foo>();
Container.Register<IBar,Bar();
var Resolved = Container.GetInstance<IFoo>();
, , . , , , , - , , Container.GetInstance (, -, , , ). !
Cheers,
PS - . .
public class BootStrapIOC
{
public ServiceContainer Container;
public BootStrapIOC(ServiceContainer container)
{
Container = container;
}
public void Start()
{
Container.Register<ISplitText, StringUtil>();
Container.Register<string, ILoader>((factory, value) => new FileViewByFileName(value));
}
}
ILoader Loader = Container.GetInstance<Func<string, ILoader>>();
ILoader l2 = Loader(TextBox1.Text);
ISplitText Splitter = Container.GetInstance<ISplitText>();
№ 1
, , interweb, , , , . ( ) , " ". winforms, , , . , . " " , , .
, Program.cs:
static class Program
{
private static ServiceContainer Container;
[STAThread]
static void Main()
{
Container = new ServiceContainer();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
BootStrapIOC Strap = new BootStrapIOC(Container);
Strap.Start();
var form = Container.GetInstance<Form1>();
Application.Run(form);
}
}
Now my question is: is my line of thinking correct in terms of winforms. It seems to make sense by changing my approach to the “above” chain and resolving from Program.cs ??
Secondly, And I'm not sure if this requires a new question in general, please tell me that I am SO no noob.
How do I set up a factory to return the correct instance of an object? One of the initial comments showed that this would be use in this scenario. Let me use a far-fetched example. Where do I need an object, but I don’t know which object is before user start / input.
My idea:
Bootstrap Container.Register ();
Factory Interface and Implementation: Put some optional parameters as well, since I want to know if this is the right / best way to do this?
public interface IFileViewerFactory
{
ILoader GetFileViewer(string FileName, string Directory = null, bool CreatingDirectory = false);
}
public class FileViewerFactory:IFileViewerFactory
{
public FileViewerFactory() { }
public ILoader GetFileViewer(string FileName, string Directory = null, bool CreatingDirectory = false)
{
if (CreatingDirectory == false)
{
if (Directory == null)
return new FileViewByFileName(FileName);
else
return new FileViewByDirectoryName(Directory, FileName);
}
else
return new FileViewByDirectoryNameCreateDirectoryOptional(Directory, FileName, CreatingDirectory);
}
}
the form:
public IFileViewerFactory FileViewerFactory { get; set; }
ButtonClick:
ILoader FileLoader = FileViewerFactory.GetFileViewer(TxtBoxFileName.Text);
Or:
ILoader FileLoader = FileViewerFacotry.GetFileViewer(TxtBoxFileName.Text,TxtBoxDirectory.Text);
So to finish, my questions are:
- " " Program.cs .
- LightInject
- factory ?
- Fugliness factory :)