views:

67

answers:

2

I searched my brains out and wasn't able to find a suitable answer, so here we go! I have the following property in each of my forms or objects:

    private RootWorkItem m_RootWorkItem;
    [RootWorkItem(Inject = true)]
    public RootWorkItem RootWorkItem {

        get {
            if (m_RootWorkItem == null) {
                m_RootWorkItem = new RootWorkItem();
            }
            return m_RootWorkItem;
        }
    }

Note that RootWorkItem is a class I have designed that contains a collection of Services (Collection). Basically, all my services are loaded from external DLL files using reflection and Activator.CreateInstance, and put into RootWorkItem.Services.

But how on earth can I actually "inject" the very first RootWorkItem created into every other RootWorkItem marked with my attribute in my program?

How do these DI patterns ACTUALLY "DO" the injection "into" a property? I know the concepts of DI but I am trying to write my own, extremely basic DI for only one single object. I've been messing with reflection tons to try and find some suitable way to do this and I'm not even closed to coming up with a right way to do it.

Edited for more clearer question: How does a DI framework/service know when an object is created that contains the property to inject?

ie:

    class MyForm : Form {
        [RootWorkItem(Inject = true)]
        public RootWorkItem RootWorkItem { get; set; }
    end class

    class Program {
        Main {
            MyForm form = new MyForm();
            form.Show();
        }
    end class

How does it know to inject the property value when the form is created, if nothing notifies the service that it was created or it needs injected?

+1  A: 

Typically, Dependency Injection frameworks use attributes and reflection to discover which fields, properties, and methods of a class require dependencies to be injected at creation time and then use reflection to actually inject the dependencies - thus getting around the normal accessor restrictions - injecting into private fields, for example.

Now, your example seems wrong to me. The attribute is on a read-only property which can't be set by reflection or any other means. I would expect your example to look like this:

[RootWorkItem(Inject = true)]
private RootWorkItem m_RootWorkItem;
public RootWorkItem RootWorkItem {

    get {
        if (m_RootWorkItem == null) {
            m_RootWorkItem = new RootWorkItem();
        }
        return m_RootWorkItem;
    }
}

Is it possible that your confusion stems from the placement of the attribute?

Also, since you are injecting the value of m_RootWorkItem into the field you would no longer need the guard on your property.

[RootWorkItem(Inject = true)]
private RootWorkItem m_RootWorkItem;
public RootWorkItem RootWorkItem {

    get {
        return m_RootWorkItem;
    }
}

So you could go one step futher and use an auto-implemented property:

[RootWorkItem(Inject = true)]
public RootWorkItem RootWorkItem { get; private set; }

Finally though, I'm not sure why the attribute type is the same as the property type and name. I would then expect something more like this:

[Inject(true)]
public RootWorkItem RootWorkItem { get; private set; }

I don't know what framework you're using so I can't comment on what the true parameter does, so I've included it verbatim.

edited due to the question being edited

You're missing the concept of the Dependency Injection framework also being an Abstract Factory.

So, you wouldn't directly create the MyForm instance. Instead you would somehow register with your DI container the MyForm type and then use the container to create the instances for you. It will then create the instance, but before returning the instance to you it would inject the dependencies (which it discovers via reflection on the attributes).

For example:

// configure at start-up
container.Register<MyForm>();

// some point later in your code
MyForm mf = container.Resolve<MyForm>();
Enigmativity
+4  A: 

You're asking the right question: "How does it know to inject the property value when the form is created, if nothing notifies the service that it was created or it needs injected?"

You're also correct when you say "if nothing notifies the service that it was created or it needs injected", then the DI framework cannot do its job.

However, the DI framework does know, because you use the DI framework to create the object that is having its dependencies injected. In this case, you use the DI framework to create your form, so it is aware of the object and can inject dependencies.

Instead of

MyForm form = new MyForm(); 
form.Show();

Do

MyForm form = DIFramework.CreateForm(typeof(MyForm));
form.Show();

Now, your DI framework knows about the object!

Essentially, new is the enemy of DI, since it means the caller is controlling construction of the object. Instead, the caller is meant to leave that responsibility to someone else, ie, the DI framework. The caller should only ever ask the DI framework to provide/construct/configure objects.

Nader Shirazie
Ah, that was what I was missing. That cleared things up for me and got me on my way. Thanks buddy!
David Anderson
No problem, and good luck.
Nader Shirazie
Nice answer, well put.
Wayne