2010-06-23 33 views
14

Hãy xem xét mã sau đây.Tiêm mảng giao diện trong Ninject

public interface IFoo { } 


public class Bar 
{ 
    public Bar(IFoo[] foos) { } 
} 


public class MyModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IFoo[]>().ToConstant(new IFoo[0]); 
     // ToConstant() is just an example 
    } 
} 


public class Program 
{ 
    private static void Main(string[] args) 
    { 
     var kernel = new StandardKernel(new MyModule()); 
     var bar = kernel.Get<Bar>(); 
    } 
} 

Khi tôi cố gắng chạy chương trình, tôi nhận được ngoại lệ sau.

Lỗi kích hoạt IFoo
Không có ràng buộc phù hợp và loại không tự ràng buộc. con đường
Kích hoạt:
2) Tiêm phụ thuộc vào IFoo foos tham số của constructor kiểu Bar
1) Yêu cầu Bar

Làm thế nào tôi có thể tiêm/bám vào một mảng trong Ninject?

Cảm ơn thời gian của bạn.

Chỉnh sửa:
Dữ liệu nhập ứng dụng của tôi do thành phần bên thứ ba tạo. Quá trình nhập áp dụng loại bộ lọc khác nhau (ví dụ: triển khai các giao diện bộ lọc khác nhau). Các quy tắc để lọc thay đổi khá thường xuyên nhưng quá phức tạp để thực hiện với cấu hình thuần túy (và một bộ lọc chính).

Tôi muốn thêm/chỉnh sửa bộ lọc dễ dàng nhất có thể. Những gì tôi có là một hội đồng nơi mà tất cả các triển khai bộ lọc được đặt trong. Tôi đã cố gắng ràng buộc mọi giao diện bộ lọc theo phương pháp sau (cung cấp một thể hiện của mọi triển khai của loại bộ lọc đó). Về cơ bản tôi muốn tránh sự cần thiết phải thay đổi mô-đun Ninject của tôi khi tôi thêm/loại bỏ các lớp lọc.

private IEnumerable<TInterface> GetInterfaceImplementations<TInterface>(IContext context) 
    { 
     return GetType().Assembly.GetTypes() 
      .Where(t => typeof (TInterface).IsAssignableFrom(t) && IsConcreteClass(t)) 
      .Select(t => Kernel.Get(t)).Cast<TInterface>(); 
    } 

Tôi cảm thấy hơi có lỗi khi bỏ qua cơ chế DI vùng chứa. Đây có phải là một thực hành không tốt? Có một thực tế phổ biến để làm những việc như vậy?

Độ phân giải:
Tôi sử dụng lớp bao bọc làm đề xuất bsnote.

Trả lời

7

Điều này phần lớn là sự trả lại câu trả lời của @ bsnote (mà tôi đã +1) có thể giúp hiểu tại sao nó hoạt động theo cách này.

Ninject (và các khuôn khổ DI/addin khác) có hai cơ sở vật chất riêng biệt:

  1. khái niệm về một trong hai liên kết với một thực hiện rõ ràng duy nhất của một dịch vụ (Get)
  2. Một cơ sở cho phép một để có được một tập hợp các dịch vụ [rằng một sau đó lập trình chọn một hoặc tập hợp trên một cách nào đó] (GetAll/ResolveAll trong Ninject)

mã ví dụ của bạn xảy ra để sử dụng sy ntax được liên kết với 2. ở trên. (ví dụ., trong MEF, thường sử dụng chú thích [ImportMany] để làm rõ điều này)

Tôi cần xem xét các mẫu (xem mã nguồn - thực sự ngắn gọn, sạch sẽ và dễ theo) để tìm giải pháp cho việc này.

Tuy nhiên, như @bsnote nói, một cách để tái cấu trúc yêu cầu của bạn là bọc mảng trong thùng chứa hoặc để có đối tượng bạn yêu cầu (ví dụ: phương pháp nhà máy hoặc loại kho lưu trữ)

Nó cũng có thể hữu ích cho bạn để giải thích trường hợp thực sự của bạn là gì - tại sao có một mảng khỏa thân? Chắc chắn có một bộ sưu tập các vật phẩm xây dựng cầu xin để được đóng gói cơ bản tất cả điều này - câu hỏi này chắc chắn không đến nhiều?

EDIT: Có một tập hợp các ví dụ quét trong các phần mở rộng mà tôi tưởng tượng sẽ tấn công rất nhiều thứ bạn đang cố gắng làm (Trong những thứ như StructureMap, loại công cụ này được tích hợp nhiều hơn. và khuyết điểm).

Tùy thuộc vào việc bạn đang cố gắng đạt được quy ước về cấu hình hay không, bạn có thể cân nhắc việc gắn một giao diện điểm đánh dấu trên từng loại plugin. Sau đó, bạn có thể rõ ràng Bind mỗi cái. Ngoài ra, đối với CoC, bạn có thể tạo vòng lặp thông thường Load() của Module trên tập hợp các triển khai bạn tạo (tức là, nhiều cá nhân Get s) trong bản chỉnh sửa của bạn.

Dù bằng cách nào, khi bạn có nhiều đăng ký tại chỗ, bạn có thể vui vẻ 'yêu cầu' một số T[] hoặc IEnumerable<T> và nhận trọn bộ. Nếu bạn muốn đạt được điều này một cách rõ ràng (nghĩa là Service Locator và tất cả nó ngụ ý - giống như bạn đang làm, bạn có thể sử dụng GetAll để nhóm chúng lại để bạn không lặp đi lặp lại theo cách bạn đã thực hiện nó.

Không chắc chắn nếu bạn đã thực hiện kết nối này hoặc nếu tôi là thiếu cái gì Dù bằng cách nào, tôi hy vọng nó dạy bạn dính vào một số mã vào câu hỏi như nó nói> 1000 từ:. P

+0

Tôi đã chọn câu trả lời này vì câu trả lời chi tiết hơn. Cảm ơn (+1) đến bsno te, quá! –

4

Đó cũng là một vấn đề đối với tôi. Ninject tiêm mỗi mục của một mảng thay vì mảng, vì vậy bạn nên có một ánh xạ được định nghĩa cho loại mục mảng. Trên thực tế không có khả năng ánh xạ mảng dưới dạng kiểu với phiên bản hiện tại của Ninject. Giải pháp là tạo một trình bao bọc xung quanh mảng. Lớp học lười biếng có thể được sử dụng ví dụ nếu nó phù hợp với bạn. Hoặc bạn có thể tạo trình bao bọc của riêng bạn.

9

Ninject hỗ trợ đa tiêm sẽ giải quyết vấn đề của bạn https://github.com/ninject/ninject/wiki/Multi-injection

public interface IFoo { } 
public class FooA : IFoo {} 
public class FooB : IFoo {} 

public class Bar 
{ 
    //array injected will contain [ FooA, FooB ] 
    public Bar(IFoo[] foos) { } 
} 

public class MyModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IFoo>().To<FooA>(); 
     Bind<IFoo>().To<FooB>(); 
     //etc.. 
    } 
} 
Các vấn đề liên quan