2

Here is what I would like to do:

public interface IInject<in T>
{
    [Inject]
    void Inject(T reference);
}

private class Foo : IInject<Bar>
{
    public Bar Bar { get; private set; }

    void IInject<Bar>.Inject(Bar reference)
    {
        Bar = reference;
    }
}

But nothing gets injected, only way that I got to work is with attribute and implicit implementation:

private class Foo : IInject<Bar>
{
    public Bar Bar { get; private set; }

    [Inject]
    public void Inject(Bar reference)
    {
        Bar = reference;
    }
}

Is there a way to do it?

Johan Larsson
  • 17,112
  • 9
  • 74
  • 88
  • What's missing from the question is *why* you want to do this. Method injection is typically not a good idea because it leads to [Temporal Coupling](http://blog.ploeh.dk/2011/05/24/DesignSmellTemporalCoupling/). – Steven Nov 27 '16 at 09:20
  • 1
    @Steven Agreed member injection is nasty. I have inherited a hairy graph that is not IoC-friendly due to cycles. Doing this is hopefully only temporary while refactoring the design to something nicer. – Johan Larsson Nov 27 '16 at 09:40

1 Answers1

2

Ninject doesn't behave like that by default. You will need to create a custom selector.*

Given your types this selector exhibits the behavior you've described,

class ExplicitSelector : Selector
{
    public ExplicitSelector(
        IConstructorScorer constructorScorer, 
        IEnumerable<IInjectionHeuristic> injectionHeuristics) 
        : base(constructorScorer, injectionHeuristics)
    {
    }

    public override IEnumerable<MethodInfo> SelectMethodsForInjection(Type type)
    {
        // Gets all implemented interface and grabs an InterfaceMapping. 
        var implementedInterfaces = type.GetInterfaces();

        foreach (var map in implementedInterfaces.Select(type.GetInterfaceMap))
        {
            for (var i = 0; i < map.InterfaceMethods.Length; i++)
            {
                // Check each interface method for the Inject attribute, and if present
                if (map.InterfaceMethods[i].CustomAttributes.Any(x => x.AttributeType == typeof (InjectAttribute)))
                {
                    // return the target method implementing the interface method. 
                    yield return map.TargetMethods[i];
                }
            }
        }

        // Defer to NInject's implementation for other bindings. 
        foreach (var mi in base.SelectMethodsForInjection(type))
        {
            yield return mi;
        }
    }
}

It's added to the kernel simply,

standardKernel.Components.Remove<ISelector, Selector>();
standardKernel.Components.Add<ISelector, ExplicitSelector>();

And then calls to get an IInject<Bar> will work as you describe, using the custom selector.


*There may be a better extension point to implement this with NInject. I'm far from an expert on NInject or it's implementation.

jdphenix
  • 15,022
  • 3
  • 41
  • 74