2012-02-08 5 views
4

Я только что перешел из Ninject в TinyIoC для инъекций зависимостей, и у меня возникли проблемы с инъекцией конструктора.Инъекция конструктора с TinyIoC

мне удалось упростить его до этого фрагмента кода:

public interface IBar { } 

public class Foo 
{ 
    public Foo(IBar bar) { } 
} 

public class Bar : IBar 
{ 
    public Bar(string value) { } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var container = TinyIoCContainer.Current; 

     string value = "test"; 
     container.Register<IBar, Bar>().UsingConstructor(() => new Bar(value)); 

     var foo = container.Resolve<Foo>(); 
     Console.WriteLine(foo.GetType()); 
    } 
} 

, который вызывает TinyIoCResolutionException быть брошенной с:

"Unable to resolve type: TinyIoCTestApp.Foo" 

и внутри этого исключения является цепь внутренних исключений:

"Unable to resolve type: TinyIoCTestApp.Bar" 
"Unable to resolve type: System.String" 
"Unable to resolve type: System.Char[]" 
"Value cannot be null.\r\nParameter name: key" 

Есть ли что-то не так с тем, как я использую конструктор в jection? Я понимаю, что я мог бы назвать

container.Register<IBar, Bar>(new Bar(value)); 

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

Любые идеи?

+0

Также: Я использую TinyIoC из Github (https://github.com/grumpydev/TinyIoC) – AndrewG

+0

Забавно, Обоснование TinyIoC имеет много общего с из [Простой инжектор] (http://simpleinjector.codeplex.com). – Steven

+1

@ @ Steven и мы оба называемся Стивен тоже .. spooky :-P –

ответ

7

Я не знаком с TinyIOC, но я думаю, что могу ответить на ваш вопрос.

UsingConstructor регистрирует лямбду, указывающую на конструктор (ctor(string)), который TinyIOC будет использовать для автоматической вставки конструктора. TinyIOC будет анализировать аргументы конструктора, находит аргумент типа System.String и пытается разрешить этот тип. Поскольку вы не зарегистрировали System.String явно (что вам не должно быть btw), разрешение IBar (и, следовательно, Foo) терпит неудачу.

Неправильное допущение, которое вы сделали, заключается в том, что TinyIOC выполнит вашу лямбду () => new Bar(value)), которой она не будет. Если вы посмотрите на метод UsingConstructor, вы сможете его использовать, чтобы он принимал Expression<Func<T>> вместо Func<T>.

Вещь, которую вы хотите, заключается в регистрации делегата фабрики, который создает это произведение. Я ожидаю, что TinyIOC будет содержать метод для этого. Это может выглядеть примерно так:

container.Register<IBar>(() => new Bar(value)); 
+2

Yep, UsingConstructor - это способ выбрать, какой конструктор использовать и для 99% время не требуется. То, что вы хотите, это перегрузка регистра, которая принимает Func и предоставляет простую фабрику для возврата вашей новой панели. –

+0

Согласен. 'UsingConstructor' полезен только тогда, когда ваш тип имеет несколько конструкторов, чего в общем случае следует избегать при выполнении DI. Из-за этого я даже оставил функцию выбора конструктора Simple Injector. – Steven

+1

Ну, несколько конструкторов, как правило, отлично с TinyIoC, потому что он принимает подход «самый жадный конструктор, который я могу успешно разрешить», но есть случаи, когда вы хотите переопределить это. –