2012-12-26 15 views
13

Giả sử tôi có các lớp sau mà tôi muốn xây dựng bằng Ninject, với các mũi tên hiển thị các phụ thuộc.Phạm vi Ninject - sử dụng cùng một trường hợp trên toàn bộ biểu đồ đang được xây dựng

A > B > D 
A > C > D 

Tôi muốn cấu hình Ninject như vậy A là scoped thoáng qua, ví dụ: mỗi khi bạn hỏi Ninject cho một A, bạn sẽ có được một cái mới. Tôi cũng muốn B và C tạm thời, bạn sẽ nhận được một cái mới mỗi khi bạn yêu cầu A. Nhưng tôi muốn D được sử dụng lại trên cả B và C. Vì vậy, mỗi khi tôi yêu cầu A, tôi muốn Ninject xây dựng một trong mỗi đối tượng, không phải hai D. Nhưng tôi không muốn Ds được tái sử dụng trên As khác nhau.

Cách tốt nhất để thiết lập điều này bằng Ninject là gì?

Cập nhật:
Sau khi một số nghiên cứu nhiều hơn, nó có vẻ như Unity có PerResolveLifetimeManager mà làm những gì tôi đang tìm kiếm. Có tương đương Ninject không?

Trả lời

13

Ninject hỗ trợ bốn được xây dựng trong object scopes out of the box: Tạm thời, Singleton, Chủ đề, Yêu cầu.

Vì vậy, không có bất kỳ phạm vi nào giống như PerResolveLifetimeManager nhưng bạn có thể triển khai dễ dàng bằng cách đăng ký phạm vi tùy chỉnh với phương thức InScope.

Khi nó bật ra có một phần mở rộng Ninject hiện có: ninject.extensions.namedscope cung cấp phương pháp InCallScope là những gì bạn đang tìm kiếm.

Tuy nhiên, nếu bạn muốn tự mình làm, bạn có thể làm với đại biểu tùy chỉnh InScope. Nơi bạn có thể sử dụng đối tượng chính IRequest cho các loại A để sử dụng nó như là đối tượng phạm vi:

var kernel = new StandardKernel(); 
kernel.Bind<A>().ToSelf().InTransientScope(); 
kernel.Bind<B>().ToSelf().InTransientScope(); 
kernel.Bind<C>().ToSelf().InTransientScope(); 
kernel.Bind<D>().ToSelf().InScope(
    c => 
     { 
      //use the Request for A as the scope object       
      var requestForA = c.Request; 
      while (requestForA != null && requestForA.Service != typeof (A)) 
      { 
       requestForA = requestForA.ParentRequest; 
      } 
      return requestForA; 
     }); 

var a1 = kernel.Get<A>();  
Assert.AreSame(a1.b.d, a1.c.d); 

var a2 = kernel.Get<A>();  
Assert.AreSame(a2.b.d, a2.c.d); 

Assert.AreNotSame(a1.c.d, a2.c.d); 

nơi các lớp mẫu là:

public class A 
{ 
    public readonly B b; 
    public readonly C c; 
    public A(B b, C c) { this.b = b; this.c = c; } 
} 

public class B 
{ 
    public readonly D d; 
    public B(D d) { this.d = d; } 
} 

public class C 
{ 
    public readonly D d; 
    public C(D d) { this.d = d; } 
} 

public class D { } 
+0

Sẽ không ngắt nếu D cũng là một phần nếu chuỗi phụ thuộc không bao gồm A? –

+0

@KevinBabcock. Không, nó sẽ không vỡ. Sau đó, đại biểu sẽ trả về 'null' tương đương với đăng ký sau:' kernel.Bind () .ToSelf(). InTransientScope(); ' – nemesv

+0

Cảm ơn bạn đã làm rõ. Câu trả lời tốt! –

1

Một thay thế là để xây dựng sự phụ thuộc mình.

var kernel = new StandardKernel(); 
kernel.Bind<A>().ToMethod(ctx => 
{ 
    var d = new D(); 
    var c = new C(d); 
    var b = new B(d); 
    var a = new A(b, c); 
    return a; 
}); 

Điều này có thể không phải là phương pháp ưa thích, nhưng nó sẽ luôn luôn xây dựng một thể hiện mới của A sử dụng một trường hợp mới của B, C, và D (nhưng tái sử dụng cùng một ví dụ của D cho BC). Bạn có thể thêm một cuộc gọi đến InTransientScope(), nhưng điều đó không bắt buộc vì đó là phạm vi mặc định.

+0

Điều này quá đặc biệt đối với những gì tôi cần. Thực tế có nhiều lớp khác nhau ở các cấp A, B, C trong mã của tôi mà tất cả đều cần chia sẻ một D cho một độ phân giải đã cho. – RationalGeek

6

Tôi đã tìm ra giải pháp cho vấn đề cụ thể của mình, đó là InCallScope được cung cấp bởi tiện ích mở rộng ninject.extensions.namedscope. Điều này hoạt động giống với khái niệm UnResolveLifetimeManager Unity.

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