Ленивая загрузка с Ninject

В любой ситуации, когда допустимо, чтобы свойство десериализации было отмечено как внутреннее, есть замечательно простое решение, которое вообще не зависит от атрибутов. Просто пометьте свойство как внутренний get, но public set:

public class JsonTest {

    public string SomeProperty { internal get; set; }

}

Это приведет к правильной десериализации с использованием настроек / resolvers / etc., Но свойство лишено из сериализованного вывода.

13
задан Aaronaught 29 March 2010 в 14:00
поделиться

1 ответ

Обновление: Мой первоначальный ответ был написан до выпуска .NET Framework 4 (вместе с Lazy ) , а другой ответ, хотя и немного более современный, все еще немного устарел. Я оставляю свой исходный ответ ниже на тот случай, если кто-то застрял на более старой версии, но не советовал бы использовать ее с последней версией Ninject или .NET.

Ninject Factory Extension - это современный способ сделать это. Он автоматически подключит любые аргументы или свойства. Для этого вам не нужна отдельная привязка - просто настройте свои службы обычным образом, а расширение сделает все остальное.

К вашему сведению, это же расширение может также подключать настраиваемые заводские интерфейсы или аргументы Func . Разница в том, что они каждый раз будут создавать новый экземпляр, так что на самом деле это фабрика, а не просто ленивое создание.Просто указываю на это, потому что в документации это не совсем ясно.


Как правило, «полное построение графа объектов» не должно быть настолько дорогостоящим, и если в класс внедряются зависимости, которые он может не использовать, это, вероятно, хороший признак того, что у класса слишком много обязанностей.

На самом деле это не ограничение Ninject как такового - если подумать, на самом деле невозможно иметь «ленивую зависимость», если только (а) внедряемая зависимость сама не является ленивым загрузчиком, например Lazy класс в .NET 4 или (б) все свойства и методы зависимости используют отложенное создание экземпляров. Что-то нужно ввести туда.

Вы можете выполнить (а) относительно легко, используя интерфейс поставщика , привязку метода (изд.: Ninject не поддерживает открытые универсальные шаблоны с привязками поставщиков) и привязку открытого универсального шаблона. тип. Предполагая, что у вас его нет.NET 4, вам придется создать интерфейс и реализацию самостоятельно:

public interface ILazy<T>
{
    T Value { get; }
}

public class LazyLoader<T> : ILazy<T>
{
    private bool isLoaded = false;
    private T instance;
    private Func<T> loader;

    public LazyLoader(Func<T> loader)
    {
        if (loader == null)
            throw new ArgumentNullException("loader");
        this.loader = loader;
    }

    public T Value
    {
        get
        {
            if (!isLoaded)
            {
                instance = loader();
                isLoaded = true;
            }
            return instance;
        }
    }
}

Затем вы можете привязать весь ленивый интерфейс - так что просто привяжите интерфейсы как обычно:

Bind<ISomeService>().To<SomeService>();
Bind<IOtherService>().To<OtherService>();

И привяжите ленивый интерфейс, используя открытые дженерики, к лямбда-методу:

Bind(typeof(ILazy<>)).ToMethod(ctx =>
{
    var targetType = typeof(LazyLoader<>).MakeGenericType(ctx.GenericArguments);
    return ctx.Kernel.Get(targetType);
});

После этого вы можете ввести аргументы / свойства ленивой зависимости:

public class MyClass
{
    [Inject]
    public MyClass(ILazy<ISomeService> lazyService) { ... }
}

Это не сделает всю операцию ленивой - Ninject все равно придется фактически создать экземпляр LazyLoader , но любые зависимости второго уровня ISomeService не будут загружены, пока MyClass не проверит значение этого lazyService .

Очевидным недостатком является то, что ILazy не реализует сам T , поэтому MyClass должен быть написан так, чтобы принимать ленивые зависимости, если вы хотите преимущество ленивой загрузки. Тем не менее, если создание определенной зависимости чрезвычайно дорого, это будет хорошим вариантом. Я почти уверен, что у вас будет эта проблема с любой формой DI, любой библиотекой.


Насколько мне известно, единственный способ сделать (b) без написания кучи кода - это использовать генератор прокси, например Castle DynamicProxy , или зарегистрировать динамический перехватчик с помощью Ninject Внутренний перехватчик . Это было бы довольно сложно, и я не думаю, что вы захотите пойти по этому пути, если только вам это не понадобится.

19
ответ дан 1 December 2019 в 19:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: