Ленивая инициализация общего делегата с помощью Ninject - PullRequest
4 голосов
/ 25 февраля 2010

Я использую Ninject 1.0 и хотел бы иметь возможность вставлять ленивые делегаты инициализации в конструкторы. Итак, учитывая общее определение делегата:

public delegate T LazyGet<T>();

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

public class Foo
{
    readonly LazyGet<Bar> getBar;

    public Foo( LazyGet<Bar> getBar )
    {
        this.getBar = getBar;
    }
}

Однако я не могу просто позвонить Bind<LazyGet<T>>(), потому что это открытый универсальный тип. Мне нужно, чтобы это был открытый обобщенный тип, чтобы мне не приходилось связывать все ленивые типы с явными типами. В приведенном выше примере должна быть возможность динамически создавать универсальный делегат, который вызывает IKernel.Get<T>().

Как этого добиться с помощью Ninject 1.0?

Ответы [ 3 ]

0 голосов
/ 06 марта 2012

Я вполне уверен, что единственный способ сделать это (без некоторого грязного кода отражения) - это связать ваш делегат с типом params. Это будет означать, что это должно быть сделано для каждого отдельного типа, который вы используете. Вы могли бы использовать BindingGenerator, чтобы сделать это навалом, но это может стать немного уродливым.

Если есть лучшее решение (чистое), я бы хотел услышать его, когда время от времени сталкиваюсь с этой проблемой.

0 голосов
/ 11 сентября 2012

С другой похожий вопрос Я ответил:

public class Module : NinjectModule
{
    public override void Load()
    {
        Bind(typeof(Lazy<>)).ToMethod(ctx => 
                GetType()
                    .GetMethod("GetLazyProvider", BindingFlags.Instance | BindingFlags.NonPublic)
                    .MakeGenericMethod(ctx.GenericArguments[0])
                    .Invoke(this, new object[] { ctx.Kernel }));
    }

    protected Lazy<T> GetLazyProvider<T>(IKernel kernel)
    {
        return new Lazy<T>(() => kernel.Get<T>());
    }
}
0 голосов
/ 17 апреля 2010

Не совсем понял вопрос, но не могли бы вы использовать рефлексию? Что-то вроде:

// the type of T you want to use
Type bindType;
// the kernel you want to use
IKernel k;

// note - not compile tested
MethodInfo openGet = typeof(IKernel).GetMethod("Get`1");
MethodInfo constGet = openGet.MakeGenericMethod(bindType);

Type delegateType = typeof(LazyGet<>).MakeGenericType(bindType);
Delegate lazyGet = Delegate.CreateDelegate(delegateType, k, constGet);

Позволит ли использование lazyGet делать то, что вы хотите? Обратите внимание, что вам также может понадобиться вызвать класс Foo с помощью отражения, если bindType не известно в контексте компиляции.

...