问题
I'm trying to scan for a set of components that implement a specific base class in the assemblies in the same directory as my application. I need to do this as a sort of plugin-style architecture, as my application uses these types to populate other components.
Ninject.Extensions.Conventions supports scanning assemblies in the local directory, so I decided to give it a shot.
The problem is that the binding generators that library provides (DefaultBindingGenerator
and RegexBindingGenerator
) will only bind components to interfaces that they implement. They won't bind to non-interface base types.
How do I use this library to bind by convention to a base class, rather than an interface?
I am using the version currently on NuGet - 2.2.0.5
My current convention-based binding code looks like this:
Kernel.Scan(x =>
{
x.FromAssembliesMatching("*.dll");
x.WhereTypeInheritsFrom<BaseType>();
// I've tried both DefaultBindingGenerator and RegexBindingGenerator
x.BindWith<DefaultBindingGenerator>();
x.InTransientScope();
});
When I try to resolve the components, nothing is returned:
var myTypes = Kernel.GetAll<BaseType>();
int count = myTypes.Count(); // Always returns zero
回答1:
In the current code base up on GitHub, you can use the BaseBindingGenerator.
In the codebase I have (the one currently on NuGet - 2.2.0.5), I solved this using a custom IBindingGenerator
. It was fairly simple to write once I looked at the sources for the existing binding generators.
public class BaseTypeBindingGenerator<TBase> : IBindingGenerator
{
private static readonly Type baseType = typeof(TBase);
public void Process( Type type, Func<IContext, object> scopeCallback,
IKernel kernel )
{
if ( type.IsInterface || type.IsAbstract || type.BaseType != baseType)
{
return;
}
kernel.Bind(baseType).To(type).InScope(scopeCallback);
}
}
I used it like this:
Kernel.Scan(x =>
{
x.FromAssembliesMatching("*.dll");
x.WhereTypeInheritsFrom<BaseType>();
x.BindWith<BaseTypeBindingGenerator<BaseType>>();
x.InTransientScope();
});
// ...
var myTypes = Kernel.GetAll<BaseType>();
int count = myTypes.Count(); // Didn't return zero!
回答2:
Just an update on Merlyn´s answer, I am using ninject extensions conventions 3.2, and the signature has changed a little bit...
public class BaseTypeBindingGenerator<TBase> : IBindingGenerator
{
private static readonly Type baseType = typeof (TBase);
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type.IsInterface || type.IsAbstract || type.BaseType != baseType)
{
return Enumerable.Empty<IBindingWhenInNamedWithOrOnSyntax<object>>();
}
return new [] { bindingRoot.Bind(baseType).To(type) };
}
}
来源:https://stackoverflow.com/questions/8499955/how-do-i-use-the-ninject-conventions-library-to-bind-to-a-base-type-that-isnt-a