21

Autofac automatically generates factories for Func<T>; I can even pass parameters.

public class MyClass
{
    public MyClass(Func<A> a, Func<int, B> b)
    {
        var _a = a();
        var _b = b(1);
    }
}

Can I do the same with Ninject? If not, what workaround can I apply?

Thanks.

Update:

Just found this post, seems the answer is no:

How do I handle classes with static methods with Ninject?

Community
  • 1
  • 1

1 Answers1

29

NB Ninject 3.0 and later has this fully supported using the Ninject.Extensions.Factory package, see the wiki:- https://github.com/ninject/ninject.extensions.factory/wiki


EDIT: NB there is a Bind<T>().ToFactory() implementation in Ninject 2.3 (which is not a fully tests supported release but is available from the CodeBetter server)

Ninject does not support this natively at the moment. We planned to add this to the next version. But support can be added easily by configuring the appropriate binding. Just load the module below and enjoy.

public class FuncModule : NinjectModule
{
    public override void Load()
    {
        this.Kernel.Bind(typeof(Func<>)).ToMethod(CreateFunc).When(VerifyFactoryFunction);
    }

    private static bool VerifyFactoryFunction(IRequest request)
    {
        var genericArguments = request.Service.GetGenericArguments();
        if (genericArguments.Count() != 1)
        {
            return false;
        }

        var instanceType = genericArguments.Single();
        return request.ParentContext.Kernel.CanResolve(new Request(genericArguments[0], null, new IParameter[0], null, false, true)) ||
               TypeIsSelfBindable(instanceType);
    }

    private static object CreateFunc(IContext ctx)
    {
        var functionFactoryType = typeof(FunctionFactory<>).MakeGenericType(ctx.GenericArguments);
        var ctor = functionFactoryType.GetConstructors().Single();
        var functionFactory = ctor.Invoke(new object[] { ctx.Kernel });
        return functionFactoryType.GetMethod("Create").Invoke(functionFactory, new object[0]);
    }

    private static bool TypeIsSelfBindable(Type service)
    {
        return !service.IsInterface
               && !service.IsAbstract
               && !service.IsValueType
               && service != typeof(string)
               && !service.ContainsGenericParameters;
    }

    public class FunctionFactory<T>
    {
        private readonly IKernel kernel;

        public FunctionFactory(IKernel kernel)
        {
            this.kernel = kernel;
        }

        public Func<T> Create()
        {
            return () => this.kernel.Get<T>();
        }
    }
}
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Remo Gloor
  • 32,665
  • 4
  • 68
  • 98
  • Thanks for the code! Will looking forward for the next version. –  Jan 31 '11 at 19:51
  • Thanks for all your hard work Remo. Is it possible to extend the code to work with Func>? – Anders Oct 26 '11 at 13:39
  • Sure it is. Change the FunctionFactory.Create method, check for IEnumerable and return GetAll instead. – Remo Gloor Oct 26 '11 at 13:47
  • Super quick response! :D But it complains that it does not find a binding for Func> (Where T is my interface).. exact error message ... Func{IEnumerable{IWorker}} 2) Injection of dependency Func{IEnumerable{IWorker}} into parameter workerFactory of constructor of type WorkflowManager – Anders Oct 26 '11 at 14:01
  • Ah, I just noticed that its up to VerifyFactoryFunction, I have to update that one for it to work.. thanks mate! – Anders Oct 26 '11 at 14:08
  • Yes I see. You have to change the VerifyFactoryFunction method as well and return true in case instanceType is an IEnumerable – Remo Gloor Oct 26 '11 at 14:10
  • Remo will this be added to the final version of 3.0? I noticed that RC2 does not support it, thanks for your hard work! – Anders Jan 08 '12 at 13:20
  • That's not correct. Ninject.Extensions.Factory is available as prerelease already – Remo Gloor Jan 08 '12 at 14:46
  • Shouldn't this be part of the Core lib? – Anders Feb 20 '12 at 09:32
  • What's the problem adding an extension? – Remo Gloor Feb 20 '12 at 09:34
  • Well, WCF and MVC are natural extensions, but to me this is a Core functionality... I'm open for module oriented architecture, but here I do not see the logic in having it separate, sorry.. – Anders Feb 20 '12 at 11:50
  • I tried adding the extension through NuGet and ended up with some build errors due to versioning of the Castle.Core dependency. Is this dependency necessary? It seems that with the module code posted above that this could just be included with Ninject as Anders suggests. – jpierson Apr 17 '14 at 05:37