2012-10-11 28 views
10

Tôi có một giao diện:bindings Ninject cho việc thực hiện điều phối của một giao diện

public interface IService 
{ 
    void DoStuff(int parm1, string parm2, Guid gimmeABreakItsAnExampleK); 
} 

Tôi muốn cấu hình Ninject (v3) bindings để tôi có thể có một "điều phối" phương pháp ngẫu nhiên gọi ra nhiều trường hợp của IService, như vậy:

public sealed class DispatcherService : IService 
{ 
    private IEnumerable<IService> _children; 

    public DispatcherService(IEnumerable<IService> children) 
    { 
     this._children = children.ToList(); 
    } 

    public void DoStuff(int parm1, string parm2, Guid gimmeABreakItsAnExampleK) 
    { 
     foreach(var child in this._children) 
     { 
      child.DoStuff(parm1, parm2, gimmeABreakItsAnExampleK); 
     } 
    } 
} 

Tuy nhiên, các ràng buộc của tôi, trông như thế này, gió lên ném một ngoại lệ trong thời gian chạy chỉ ra một sự phụ thuộc theo chu kỳ:

this.Bind<IService>().To<DispatcherService>(); 

this.Bind<IService>().To<SomeOtherService>() 
    .WhenInjectedExactlyInto<DispatcherService>(); 
this.Bind<IService>().To<YetAnotherService>() 
    .WhenInjectedExactlyInto<DispatcherService>(); 

Điều này có khả thi không? Nếu vậy, tôi đang làm gì sai? Liệu ninja có thể thoát khỏi sự phụ thuộc chu kỳ này?

+0

Tại sao bạn cần 'WhenInjectedExactlyInto', tại sao không chỉ' To'? – casperOne

+0

Vì 'WhenInjectedExactlyInto' ngăn' SomeOtherService' và 'YetAnotherService' khỏi bị tiêm vào bất cứ thứ gì ngoài' DispatcherService'. Tôi đã sử dụng một cách tiếp cận tương tự để "bọc" (xem http://stackoverflow.com/questions/6752674/dependency-injection-how-to-configure-interface-bindings-for-wrapping), nhưng tôi đang cố gắng làm cho nó hoạt động cho trường hợp đa tiêm. – FMM

+0

Bạn đã xem xét các tiện ích mở rộng của Môi giới sự kiện khác nhau - tất cả đều làm những thứ mà các ví dụ của bạn làm ở mức độ sâu. OK, bạn nói đó chỉ là một ví dụ, tôi sẽ im lặng! –

Trả lời

2

Nếu phối của bạn là chỉ IService đó đang xảy ra để có một danh sách các IServices như một tham số, điều này không làm việc (Tôi đã thử nghiệm):

kernel.Bind<IService>().To<DispatcherService>().When(x => x.IsUnique); 
this.Bind<IService>().To<SomeOtherService>() 
    .WhenInjectedExactlyInto<DispatcherService>(); 
this.Bind<IService>().To<YetAnotherService>() 
    .WhenInjectedExactlyInto<DispatcherService>(); 

Lý do mà When khoản làm việc cho trường hợp này là trường IsUnique của IRequest được đặt thành true khi hàm tạo của bạn gọi một phiên bản dịch vụ duy nhất. Vì số điện thoại DispatcherService của bạn cho số IEnumerable, giá trị là false khi kích hoạt DispatcherService. Điều đó ngăn cản sự phụ thuộc vòng tròn xảy ra.

Thực sự, bất kỳ cách chính xác nào để cho hạt nhân không cố gắng tiêm DispatcherService vào chính nó sẽ hoạt động (đây chỉ là một ví dụ hữu ích).

Edit: Cách rõ ràng hơn chỉ đơn giản là ngắn circuiting phụ thuộc vòng tròn của bạn dường như là điều này:

kernel.Bind<IService>().To<DispatcherService>().When(
    request => request.Target.Member.DeclaringType != typeof (DispatcherService)); 
+0

Cảm ơn bạn, thưa ông! Nếu bạn có thể cập nhật câu trả lời của mình để bao gồm một số thông tin trên cờ 'IsUnique' của 'IRequest', câu trả lời và tiền thưởng sẽ được chuyển đến bạn. – FMM

+0

@FMM Cảm ơn. Tôi hy vọng lời giải thích của tôi không quá vụng về :) –

+0

Tuyệt vời, cảm ơn! Ví dụ đơn lẻ so với nhiều trường hợp không rõ ràng ngay từ tên 'IsUnique', IMHO. – FMM

1

Tôi phải thừa nhận rằng tôi không phải là quen thuộc với các API Ninject, nhưng tôi nghĩ rằng điều này sẽ làm các trick:

kernel.Bind<IService>().To<DispatcherService>(); 

kernel.Bind<IEnumerable<IService>>().ToMethod(() => new IService[] 
{ 
    kernel.Get<SomeOtherService>(), 
    kernel.Get<YetAnotherService>(), 
}); 
+0

Không hoạt động. Vẫn gây ra sự phụ thuộc theo chu kỳ. Sử dụng 'IService []' thay vì 'IEnumerable ' cũng không có tác động. – FMM

+0

Tôi xin lỗi. Tôi nghĩ rằng tôi hiểu lý do tại sao (nhưng không chắc chắn làm thế nào để giải quyết điều này trong Ninject). Ninject cho phép nhiều cuộc gọi đến 'Bind ()' với các triển khai khác nhau và Ninject sẽ sử dụng tất cả các cuộc gọi đó để giải quyết bộ sưu tập.(đây là một tính năng hầu hết các container có và nó là một cái gì đó tôi không thích rất nhiều). Tôi nghĩ rằng điều này sẽ ghi đè đăng ký của bạn 'IEnumerable '. Tôi nghĩ rằng thủ thuật là để đăng ký một 'IList ' hoặc 'IService []' và để cho 'DispatcherService' của bạn phụ thuộc trực tiếp vào' IList 'hoặc 'IService []' này. – Steven

0

Bạn có thể tách riêng hai tập con (hoặc Dispatcher hoặc recievers) ra khỏi bằng cách làm cho một trong số họ có tên là Binding, và sau đó sử dụng tên như một cách để nuôi một cái khác (hoặc thông qua một NamedAttribute hoặc trong hệ thống dây điện của bạn)

+0

Ví dụ về mã? Nó cũng giống như constructor 'DispatcherService' sau đó sẽ cần các thuộc tính cụ thể của Ninject, mà tôi muốn tránh. – FMM

+0

Xin lỗi, quá bận rộn thời điểm này - ping lại nếu bạn không thể sắp xếp nó mà không có ví dụ. Có một cái nhìn trên wiki cho các ví dụ ràng buộc có tên ... –

1

Tại sao không loại bỏ IService trong DispatcherService và gọi nó IDispatcherService và làm cho các dịch vụ được gọi (nhận) thực hiện IService?