2010-02-25 2 views
4

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

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?

+0

Инъекционного зависимость, от которой * явно * Ленивая есть, IMO, дырявая абстракция. См. Здесь для получения дополнительной информации: http://blog.ploeh.dk/2010/01/20/RebuttalConstructorOverinjectionAntipattern.aspx –

+0

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

+0

Довольно честно :) Во всяком случае, я никогда не хотел, чтобы мой комментарий был пренебрежительным. Однако сообщение, на которое я указал, делает выход из-за явной реализации лени как декоратора. Я просто не хотел предлагать это в качестве ответа, потому что вы могли бы получить правильный ответ Ninject от кого-то другого :) –

ответ

0

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

// 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 не известен в контексте компиляции.

+0

Спасибо за код, но он «голый» - t показать, как это зарегистрировано в Ninject. Я могу легко написать код, как и вы, но как я могу сообщить Ninject об этом, чтобы при создании экземпляра типа, который принимает ленивого делегата, он привязывает его к собственному методу Get? То, что я делаю, кажется мне совершенно понятным: я хочу привязать этот параметр к собственному методу Get, чтобы объект, запрашивающий экземпляр типа, вызывает Ninject's Get. –

0

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

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

0

От another similar question Я ответил:

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>()); 
    } 
} 
Смежные вопросы