2011-10-31 24 views
8

Tôi muốn để ràng buộc nhiều triển khai của một dịch vụ và có tất cả trong số họ gọi cùng một lúc:Ninject Multicasting

var kernel = new StandardKernel(); 

kernel.Bind<IBreakfast>.To<Spam>(); 
kernel.Bind<IBreakfast>.To<Eggs>(); 
kernel.Bind<IBreakfast>.To<MoreSpam>(); 

kernel.Get<IBreakfast>().Eat(); // call Eat method on all three bound implementations 

Ninject không như thế, và sẽ ném một ngoại lệ về việc có nhiều ràng buộc. Có cách nào tôi có thể nhận được xung quanh lỗi đó, và có tất cả các triển khai được gọi là?

Ngoài ra, các cuộc gọi Bind<> có thể nằm trong các dự án khác nhau có thể hoặc không được tải trong thời gian chạy, do đó việc tạo một triển khai duy nhất để gọi chúng sẽ không hoạt động. Đây là một phần của kiến ​​trúc plug-in cho trang web ASP.NET MVC 3.

Trả lời

12

Nếu bạn sử dụng chức năng tiêm xây dựng và có tham số List<IBreakfast>, thì Ninject sẽ xây dựng danh sách bằng cách sử dụng tất cả các ràng buộc của bạn. Sau đó, bạn có thể gọi Eat trên các trường hợp này.

Bạn có thể sử dụng mẫu này để lấy Ninject để tạo danh sách các plugin của bạn chẳng hạn.

[Test] 
    public void Test() 
    { 
     IKernel kernel = new StandardKernel(); 

     kernel.Bind<IBreakfast>().To<Eggs>(); 
     kernel.Bind<IBreakfast>().To<Spam>(); 
     kernel.Bind<IBreakfast>().To<MoreSpam>(); 

     var bling = kernel.Get<Bling>(); 
    } 

    private class Bling 
    { 
     public Bling(List<IBreakfast> things) 
     { 
      things.ForEach(t => t.Eat()); 
     } 
    } 

    private interface IBreakfast 
    { 
     void Eat(); 
    } 

    private class Ingrediant : IBreakfast 
    { 
     public void Eat(){Console.WriteLine(GetType().Name);} 
    } 

    private class Eggs : Ingrediant{} 
    private class Spam : Ingrediant{} 
    private class MoreSpam : Ingrediant { } 

Output:

Trứng
Spam
MoreSpam

+0

Tôi sẽ cố gắng này vào buổi sáng khi tôi nhận được để làm việc, nhưng sẽ không Ninject ném một lỗi trên cuộc gọi thứ hai cho 'Bind <> () .Để <>() '? – MikeWyatt

+5

@MikeWyatt: Không, nhiều 'Bind' là tốt. Không có gì là tốt với 'Get ' cho kết quả nhiều hơn một mục 'Single'. Nếu bạn muốn thực hiện điều đó, bạn có thể sử dụng 'GetAll ' (hoặc sử dụng việc sắp xếp nhiều lần lên nhiều đăng ký qua 'Danh sách ', 'T []' hoặc 'IEnumerable 'như được đề xuất) (Và những người đăng/mã như các bài kiểm tra không bao giờ đăng nội dung mà thổi lên!). Lưu ý rằng Ninject không có nhiều bất kỳ để tạo ra một Composite phức tạp để phát đa hướng các cuộc gọi theo cách bạn muốn. –

+1

Công trình này tuyệt vời. Cảm ơn. – MikeWyatt

0

Bạn không thể gắn nhiều lớp bê tông để giao diện một lần duy nhất, đó là chống lại quy tắc DI.

Cơ bản bạn muốn làm là khởi tạo vài trường hợp cụ thể và gọi phương thức của chúng.

Bạn có thể muốn kiểm tra này:

Bind<IBreakfast>.To<Spam>().Named("Spam"); 
Bind<IBreakfast>.To<Eggs>().Named("Eggs"); 
Bind<IBreakfast>.To<MoreSpam>().Named("MoreSpam"); 

var breakfastList = new List() { "Spam", "Eggs", "MoreSpam" }; 
breakfastList.ForEach(item => kernel.Get<IBreakfast>(item).Eat()); 
+0

Tôi sẽ không nói rằng nó chống lại các quy tắc DI. Nếu tên miền của bạn gặp vấn đề một cách tự nhiên thì luôn có mối quan hệ một-nhiều giữa một giao diện và các lớp cụ thể, vậy thì tốt. Các thùng chứa IoC tinh vi cho phép bạn lập mô hình kịch bản này. Kịch bản plugin của OP là một trong những kiểu mô hình này. –

+3

Cách tiếp cận này không hoạt động với kiến ​​trúc trình cắm thêm bởi vì, theo định nghĩa, bạn không biết trình cắm nào sẽ có mặt. – Bevan