Остановить Ninject от автоматической привязки Func‹T, T, bool›

У меня есть PriorityQueue, которая принимает Func в качестве параметра построения.

public PriorityQueue(ISomeOtherInjectedThing other, Func<T, T, bool> cmp_func) {...}

Я связал это с помощью Ninject:

Bind(typeof (IPriorityQueue<,>)).To(typeof(PriorityQueue<,>));

У нас была странная ошибка в коде, и как часть этого мы заметили, что Ninject, кажется, генерирует объект Func и вставляет его в нашу приоритетную очередь, но у нас нет привязки для этого. Фабрика должна была выдать исключение активации, так как мы не передали требуемую функцию сравнения. Это не так, и если я отлаживаю, я нахожу это:

Ninject.dll!Ninject.KernelBase.Resolve.AnonymousMethod__c(Ninject.Planning.Bindings.IBinding binding) Line 386 + 0x5a bytes C#

Как я могу заставить Ninject генерировать исключение, как и ожидалось, вместо того, чтобы молча генерировать Func‹> для внедрения?


person Wilbert    schedule 21.07.2014    source источник


Ответы (1)


Привязка Func-Auto к Func-Factory является функцией Ninject.Extensions.Factory. См. источник: FuncModule.cs< /а>

Если вы создадите специальную привязку для Func<T, T>, она все равно переопределит общую привязку, созданную FuncModule. Но, как вы заметили, исключений не будет, если вы не создадите эту конкретную привязку.

Самый простой способ избавиться от стандартной (открытой) привязки — избавиться от расширения Factory.

Но это, наверное, несколько радикально. Вместо этого вы также можете отключить Автоматическую загрузку расширений. :

var kernel = new StandardKernel(new NinjectSettings {LoadExtensions = false});

Тогда вам придется динамически загружать расширения — это делается путем загрузки их NinjectModule реализаций. Например:

IKernel.Load<FuncModule>();

Конечно, FuncModule вы не хотите загружать, мы делаем все это, чтобы избавиться от него. Но вам придется сделать это для всех других модулей расширения, которые вам действительно нужны. Наконец, вам нужно будет создать все привязки расширений Factory, которые вам нужны:

if (!this.Kernel.GetBindings(typeof(Func<IContext, IResolutionRoot>)).Any())
{
    this.Bind<Func<IContext, IResolutionRoot>>().ToMethod(ctx => context => context.Kernel);
}

this.Bind<FuncProvider>().ToSelf().InSingletonScope();
this.Bind<IFunctionFactory>().To<FunctionFactory>();
this.Bind<IInstanceProvider>().To<StandardInstanceProvider>();

#if !SILVERLIGHT_20 && !WINDOWS_PHONE && !NETCF_35
this.Bind<IInterceptor>().To<FactoryInterceptor>()
    .When(request => typeof(IFactoryProxy).IsAssignableFrom(request.Target.Member.ReflectedType));
#endif

Примечание. Если вы действительно используете Func-Factory, я бы рекомендовал «игнорировать» проблему. Теперь вы знаете, где искать, если проблема снова возникнет. Если это отдельная проблема, вы также можете заменить свой Func<,> интерфейсом, сделав вещи более явными (чистый код). Конечно, это ни в коем случае не идеальное решение. Это просто один из трудных выборов, которые нужно сделать ;-)

person BatteryBackupUnit    schedule 21.07.2014
comment
Правильно ли я понимаю: если я просто перестану использовать заводское расширение (= не устанавливаю заводское расширение nupkg), проблема исчезнет? - person Wilbert; 21.07.2014
comment
Но я также думаю, что Factory Extensions предоставляет некоторые очень ценные функции. Поэтому я бы либо заменил Func<> конкретными интерфейсами, либо использовал только половину расширения, отключив автозагрузку и создав собственный набор привязок для расширения Factory - как описано в ответе. - person BatteryBackupUnit; 21.07.2014
comment
Это не сработает для меня. Функция сравнения PriorityQueue‹T,T,bool› не предназначена для привязки, а специфицируется в коде (поскольку у нас могут быть сравнения ‹, ‹=, ›, ›= для всех объектов). Ошибка в нашем коде заключалась в том, что фабричным методом был Create() вместо Create(Func‹...›), и он не был обнаружен из-за отсутствия генерирования исключений. Я чувствую, что это ошибка в фабричных расширениях, поскольку поведение, которое будет молча предоставлять привязки для Func‹›, определенно не соответствует ожиданиям большинства пользователей. - person Wilbert; 21.07.2014
comment
Я согласен, что было бы лучше, если бы это было поведение отказа (возможно, отдельный пакет nuget Ninject.Extensions.FuncFactory) вместо отказа. Так что да, это далеко не идеально. Использование только половины (без привязки Func<>) расширений по-прежнему будет работать для вас, но требует некоторой работы (загрузка всех модулей расширения вручную). - person BatteryBackupUnit; 21.07.2014
comment
Кстати. AFAIK AutoFac и Unity ведут себя одинаково в отношении Func<> и Lazy<> - они также автоматически связаны. - person BatteryBackupUnit; 21.07.2014
comment
Я написал отчет об ошибке на github: github.com/ninject/ninject.extensions. factory/issues/21, посмотрим, что из этого выйдет. - person Wilbert; 21.07.2014