Neil
Neil

Reputation: 5239

Problems writing/compling generic Ninject binding

I have the following class which I'm using to do a specific query on the database and creating a presentation model of data to pass back to the client browser.

public class SpecificFooQuery: IPresentationQuery<FooRequest, FooResult>
{
    public SpecificFooQuery(ILogger logger, DbContext context)
    {
        this.logger = logger;
        this.context = context;
    }

    public FooResult Get(FooRequest request)
    {
        return new FooResult { ... };
    }
}

It implements the following generic interface

public interface IPresentationQuery<TRequest, TResult>
    where TRequest : class
    where TResult : class
{
    TResult Get(TRequest request);
}

But I'm having problems writing a ninject instantiation which will create my object for me. This doesn't work but I've not really got any further than this so far.

kernel.Bind<IPresentationQuery<FooResult, FooRequest>>().To<SpecificFooQuery>();

Can anyone help me out with this, I'm not really sure where I'm going wrong or what I need to do to make this work.


Error   1   
The type 'SpecificFooQuery' cannot be used as type parameter 
'TImplementation' in the generic type or method   
'Ninject.Syntax.IBindingToSyntax<T1>.To<TImplementation>()'. 
There is no implicit reference conversion from 
'SpecificFooQuery' to 'IPresentationQuery<FooResult,FooRequest>'.   

Upvotes: 2

Views: 668

Answers (2)

Steven
Steven

Reputation: 172865

I know this question is about Ninject, but if you're doing this kind of generic trickery, you might want to try Simple Injector. It allows you to register all IPresentationQuery<TRequest, TResult> implementations in one single line of code like this:

container.RegisterManyForOpenGeneric(
    typeof(IPresentationQuery<,>),
    typeof(IPresentationQuery<,>).Assembly);

RegisterManyForOpenGeneric is an extension method on the SimpleInjector.Extensions project which can be downloaded from NuGet just as Simple Injector is.

And wrapping all those implementations with a generic decorator would also be a one-liner:

container.RegisterDecorator(
    typeof(IPresentationQuery<,>),
    typeof(ValidationPresentationQueryDecorator<,>));

Nice about Simple Injector is that it is blazingly fast, even when dealing with generic decorators. And Simple Injector even respects your generic type constraints. You add a generic type constraint to a decorator to prevent it from being wrapped to certain types. And if that's not possible, you can also register a conditional decorator like this:

container.RegisterDecorator(
    typeof(IPresentationQuery<,>),
    typeof(ValidationPresentationQueryDecorator<,>),
    context => NeedsValidation(context.ImplementationType));

Even this registration is optimized and the supplied predicate will only be called once per closed generic type. The RegisterDecorator method is part of the same Extensions project as RegisterManyForOpenGeneric is.

Upvotes: 3

Peit
Peit

Reputation: 892

It seems that the order of your type parameters is wrong. You try to bind IPresentationQuery<FooResult, FooRequest> to a implementation of IPresentationQuery<FooRequest, FooResult>.

Upvotes: 1

Related Questions