Как использовать библиотеку Ninject Conventions для привязки к базовому типу, который не является интерфейсом? - PullRequest
4 голосов
/ 14 декабря 2011

Я пытаюсь найти набор компонентов, которые реализуют определенный базовый класс в сборках в том же каталоге, что и мое приложение. Мне нужно сделать это как своего рода архитектуру в стиле плагина, так как мое приложение использует эти типы для заполнения других компонентов.

Ninject.Extensions.Conventions поддерживает сканирование сборок в локальном каталоге, поэтому я решил попробовать.

Проблема в том, что предоставляемые библиотекой генераторы привязки (DefaultBindingGenerator и RegexBindingGenerator) будут связывать компоненты только с интерфейсами, которые они реализуют. Они не будут привязываться к неинтерфейсным базовым типам.

Как использовать эту библиотеку для условного связывания с базовым классом, а не с интерфейсом?

Я использую версию, в настоящее время установленную на NuGet - 2.2.0.5

Мой текущий код привязки на основе соглашения выглядит следующим образом:

Kernel.Scan(x =>
{
    x.FromAssembliesMatching("*.dll");
    x.WhereTypeInheritsFrom<BaseType>();

    // I've tried both DefaultBindingGenerator and RegexBindingGenerator
    x.BindWith<DefaultBindingGenerator>();

    x.InTransientScope();
});

Когда я пытаюсь разрешить компоненты, ничего не возвращается:

var myTypes = Kernel.GetAll<BaseType>();
int count = myTypes.Count(); // Always returns zero

Ответы [ 2 ]

6 голосов
/ 14 декабря 2011

В текущий код базируется на GitHub , вы можете использовать BaseBindingGenerator.

В кодовой базе, которая у меня есть (в настоящее время на NuGet - 2.2.0.5), я решил эту проблему с помощью пользовательского IBindingGenerator. Это было довольно просто написать, как только я посмотрел на источники для существующих генераторов связывания .

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);
    }
}

Я использовал это так:

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!
0 голосов
/ 13 августа 2016

Просто обновление ответа Мерлина, я использую условные соглашения расширений 3.2, и подпись немного изменилась ...

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) };
    }
}
...