2010-02-09 39 views
61

Tôi quyết định bắt đầu sử dụng Ninject và gặp phải sự cố. Giả sử tôi có kịch bản sau đây. Tôi có giao diện IService và 2 lớp đang triển khai giao diện này. Và tôi cũng có một lớp học, trong đó có một nhà xây dựng nhận IService và int. Làm thế nào tôi có thể tạo một thể hiện của lớp này với Ninject (Tôi không muốn hardwire int này, tôi muốn vượt qua nó mỗi khi tôi nhận được một ví dụ)?Tạo một cá thể bằng Ninject với các tham số bổ sung trong hàm tạo

Dưới đây là một số mã minh họa tình hình:

interface IService 
{ 
    void Func(); 
} 

class StandardService : IService 
{ 
    public void Func() 
    { 
     Console.WriteLine("Standard"); 
    } 
} 

class AlternativeService : IService 
{ 
    public void Func() 
    { 
     Console.WriteLine("Alternative"); 
    } 
} 


class MyClass 
{ 
    public MyClass(IService service, int i) 
    { 
     this.service = service; 
    } 

    public void Func() 
    { 
     service.Func(); 
    } 

    IService service = null; 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     IKernel kernel = new StandardKernel(new InlineModule(
      x => x.Bind<IService>().To<AlternativeService>(), 
      x => x.Bind<MyClass>().ToSelf())); 

     IService service = kernel.Get<IService>(); 

     MyClass m = kernel.Get<MyClass>(); 
     m.Func(); 
    } 
} 

Trả lời

84

Các With.ConstructorArgument tồn tại trong 1.0 cho mục đích này. Trong 2.0, cú pháp đã thay đổi một chút: - With.Parameters.ConstructorArgument with ninject 2.0

Xem Inject value into injected dependency để biết thêm chi tiết và ví dụ về cách sử dụng ngữ cảnh, nhà cung cấp và đối số để truyền nội dung như thế này xung quanh chính xác hơn.

EDIT: Như Steven đã được bầu vào giả vờ nhận xét của tôi là không thích hợp, tôi muốn tốt nhất làm cho rõ ràng những gì tôi đang nói với một số ví dụ (đối với 2.0):

MyClass m = kernel.Get<MyClass>(new ConstructorArgument("i", 2)); 

để mắt của tôi là rất rõ ràng và nói chính xác những gì đang xảy ra.

Nếu bạn đang ở một vị trí mà bạn có thể xác định các tham số trong một cách toàn diện hơn, bạn có thể đăng ký một nhà cung cấp và làm điều đó như thế này:

class MyClassProvider : SimpleProvider<MyClass> 
{ 
    protected override MyClass CreateInstance(IContext context) 
    { 
     return new MyClass(context.Kernel.Get<IService>(), CalculateINow()); 
    } 
} 

Và đăng ký nó như thế này:

x => x.Bind<MyClass>().ToProvider(new MyClassProvider()) 

NB số CalculateINow() là nơi bạn đặt trong logic của mình như trong câu trả lời đầu tiên.

Hoặc làm cho nó phức tạp hơn như thế này:

class MyClassProviderCustom : SimpleProvider<MyClass> 
{ 
    readonly Func<int> _calculateINow; 
    public MyClassProviderCustom(Func<int> calculateINow) 
    { 
     _calculateINow = calculateINow; 
    } 

    protected override MyClass CreateInstance(IContext context) 
    { 
     return new MyClass(context.Kernel.Get<IService>(), _calculateINow()); 
    } 
} 

nào bạn muốn đăng ký như sau:

x => x.Bind<MyClass>().ToProvider(new MyClassProviderCustom(() => new Random().Next(9))) 

UPDATE: Mới hơn cơ chế mà triển lãm nhiều mẫu cải tiến với ít soạn sẵn hơn trên là được thể hiện trong tiện ích mở rộng Ninject.Extensions.Factory, xem: https://github.com/ninject/ninject.extensions.factory/wiki

Như đã nêu trước đó, if you need to pass a different parameter each time and you have multiple levels in the dependency graph, you might need to do something like this.

Xem xét cuối cùng là vì bạn chưa chỉ định Using<Behavior>, nó sẽ mặc định thành mặc định/được mặc định trong các tùy chọn cho hạt nhân (TransientBehavior trong mẫu), có thể khiến thực tế là nhà máy tính i trên moot bay [ví dụ, nếu nó đối tượng đã được lưu trữ]

Bây giờ, để làm rõ một số điểm khác trong các ý kiến ​​được FUDed và bóng hơn. Một số điều quan trọng cần xem xét về việc sử dụng DI, có thể là Ninject hoặc bất cứ điều gì khác là để:

  1. Có càng nhiều càng tốt thực hiện bằng cách tiêm constructor vì vậy bạn không cần phải sử dụng thuộc tính cụ chứa và thủ thuật.Có một bài đăng trên blog tốt trên đó được gọi là Your IoC Container is Showing.

  2. Giảm thiểu mã đi tới vùng chứa và yêu cầu nội dung - nếu không mã của bạn được kết hợp với a) vùng chứa cụ thể (mà CSL có thể thu nhỏ) b) cách thức toàn bộ dự án của bạn được đặt. Có những bài đăng trên blog tốt cho thấy rằng CSL không làm những gì bạn nghĩ. Chủ đề chung này được gọi là Service Location vs Dependency Injection. CẬP NHẬT: Xem http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx để biết lý do chi tiết và đầy đủ.

  3. Giảm thiểu sử dụng tĩnh và độc thân

  4. Đừng cho rằng chỉ có một [global] container và rằng đó là OK để chỉ đòi hỏi nó bất cứ khi nào bạn cần nó như một biến toàn cục tốt đẹp. Việc sử dụng chính xác nhiều mô-đun và Bind.ToProvider() cung cấp cho bạn cấu trúc để quản lý việc này. Bằng cách đó mỗi hệ thống riêng biệt có thể làm việc trên riêng của mình và bạn sẽ không có các thành phần cấp thấp được gắn liền với các thành phần cấp cao vv

Nếu ai đó muốn điền vào các liên kết đến các blog mà tôi đang đề cập Tôi rất cảm kích rằng (tất cả chúng đều được liên kết từ các bài đăng khác trên SO, vì vậy tất cả điều này chỉ là bản sao UI đã được giới thiệu với mục đích tránh nhầm lẫn với câu trả lời sai lệch.)

, nếu chỉ có Joel có thể đến và thực sự đặt tôi thẳng vào cú pháp tốt đẹp và/hoặc cách đúng để làm điều này!

UPDATE: Trong khi câu trả lời này rõ ràng là hữu ích từ số lượng upvotes nó thu hút, tôi muốn thực hiện các khuyến nghị sau:

  • Các cảm giác ở trên vì nó là một chút ngày và phải trung thực phản ánh một rất nhiều suy nghĩ không hoàn toàn gần như cảm thấy xấu hổ kể từ khi đọc Dependency Injection in .net - Chạy và mua nó ngay bây giờ - nó không chỉ là về DI, nửa đầu là một điều trị hoàn chỉnh của tất cả các mối quan tâm kiến ​​trúc xung quanh nó từ một người đàn ông đã dành quá nhiều thời gian ở đây treo xung quanh thẻ tiêm phụ thuộc.
  • Go đọc Mark Seemann's top rated posts here on SO right now - bạn sẽ tìm hiểu kỹ thuật có giá trị từ mỗi một
+0

Tốt để tìm thấy điều này, vì tài liệu rất xa phía sau .... – Elton

Các vấn đề liên quan