2012-09-10 28 views
17

Tôi hiện đang sử dụng đoạn mã sau:gì sẽ xảy ra với việc sử dụng tuyên bố khi tôi chuyển sang Dependency Injection

public class MyProvider 
{ 
    public MyProvider() 
    { 
    } 

    public void Fetch() 
    { 
     using (PopClient popClient = new PopClient()) 
     { 
      .... 
     } 
    } 
} 

Bởi vì tôi muốn để có thể kiểm tra đơn vị phương pháp Fetch và do thực tế rằng tôi có thể' t mock PopClient, tôi tạo ra một giao diện và một lớp bao bọc mà gọi vào PopClient. đang cập nhật của tôi trông giống như:

public class MyProvider 
{ 
    private readonly IPopClient popClient; 

    public MyProvider(IPopClient popClient) 
    { 
     this.popClient = popClient; 
    } 

    public void Fetch() 
    { 
     using (var pop3 = popClient) 
     { 
      .... 
     } 
    } 
} 

Tôi đang sử dụng Ninject cho dependency injection và tôi không hoàn toàn chắc chắn những gì loại có hiệu lực báo cáo kết quả sử dụng sẽ có trong mã cập nhật kể từ Ninject đã tạo một thể hiện của PopClient và tiêm nó vào hàm tạo.

Tuyên bố sử dụng sẽ vứt bỏ đối tượng pop3 và để đối tượng popClient một mình để Ninject có thể xử lý nó hoặc câu lệnh sử dụng sẽ can thiệp vào Ninject không?

Cách tiếp cận phù hợp trong trường hợp này là gì? Mọi hiểu biết sẽ rất hữu ích.

+0

Nếu bạn vứt bỏ popClient, điều gì xảy ra với đối tượng MyProvider?! Không phải nó cũng được xử lý sao? Bởi vì chỉ còn lại một thành viên chỉ đọc được xử lý trong lớp. Nếu nó là như vậy, tôi nghĩ rằng nó là tốt hơn để đặt một phương pháp vứt bỏ cho lớp MyProvider. –

Trả lời

14

Biến pop3 sẽ được cung cấp tài liệu tham khảo cùng với một đối tượng IPopClient rằng popClient có, vì vậy khi báo cáo kết quả using kết thúc, các đối tượng được gọi bởi cả các biến địa phương và dụ sẽ là Dispose() d, có lẽ đặt nó trong trạng thái không nhất quán để sử dụng thêm.

Nếu bạn muốn sử dụng nhiều trường hợp của IPopClient, mỗi Fetch() cuộc gọi, những gì bạn cần làm là tiêm một "phương pháp nhà máy":

public class MyProvider 
{ 
    private readonly Func<IPopClient> createPopClient; 

    public MyProvider(Func<IPopClient> popClientFactory) 
    { 
     this.createPopClient = popClientFactory; 
    } 

    public void Fetch() 
    { 
     using (var pop3 = createPopClient()) 
     { 
      .... 
     } 
    } 
} 

Bây giờ, khi bạn gọi Fetch(), nó sẽ thực hiện nhà máy phương pháp sẽ trả về một tham chiếu mới đến một IPopClient, có thể được sử dụng và sau đó xử lý mà không ảnh hưởng đến bất kỳ cuộc gọi nào khác đến phương thức đó.

AutoFac hỗ trợ tiêm các phương thức nhà máy cho các loại đã đăng ký mà không cần bất kỳ thiết lập bổ sung nào (do đó tên của nó, tôi nghĩ); Tôi tin rằng khi cấu hình một thùng chứa Ninject, bạn phải đăng ký một "getter" một cách rõ ràng làm phương thức factory cho một kiểu trả về (có thể đơn giản như lambda ()=>new PopClient() hoặc nó có thể sử dụng một lời gọi đến phương thức phân giải của container).

+1

tốt hơn để tạo giao diện nhà máy. Mục đích rõ ràng hơn. 1 cách cho mẫu nhà máy – jgauffin

+0

Miễn là bạn có 'Ninject.Extensions.Factory.dll' trong AppDomain.BaseDirectory, Func được tự động phát hiện - xem [wiki' Ninject.Extensions.Factory'] (https: // github.com/ninject/ninject.extensions.factory/wiki/Func) (nghĩa là không cần phải đăng ký bất kỳ thứ gì) –

+0

Tôi sẽ làm lại bình luận của @jgauffin ở trên. Một giao diện nhà máy là một công việc nhiều hơn một chút, nhưng nó sẽ trả hết trong thời gian dài. Mục đích sẽ rõ ràng hơn, và chế nhạo cũng dễ dàng hơn. – Pflugs

1

Khi thiết lập các ràng buộc của bạn, kê khai phạm vi:

https://github.com/ninject/ninject/wiki/Object-Scopes

Ninject sẽ gọi vứt bỏ trên các đối tượng nó tạo cho bạn, do đó hãy chắc chắn rằng bạn viết lên phương pháp dispose của bạn trong bất kỳ đối tượng nào bạn trao cho Ninject để xử lý.

+0

Vấn đề là với nó được thiết lập theo cách hiện tại, MyProvider chỉ nhận được một cá thể của đối tượng IPopClient để sử dụng; điều đó có nghĩa là nếu mã thực hiện nhiều lệnh gọi Fetch() bằng một cá thể của MyProvider, điều này sẽ thất bại bất kể phạm vi đăng ký của IPopClient là gì. – KeithS

+0

Có, phương thức Fetch sẽ được gọi nhiều lần vì vậy trong mã hiện tại (không có DI), tôi luôn được đảm bảo một phiên bản pop mới vì sử dụng câu lệnh. Trong mã DI tôi tin rằng phạm vi thoáng qua sẽ chỉ tạo ra một cá thể sẽ được sử dụng bởi nhiều cuộc gọi và câu lệnh sử dụng sẽ hủy bỏ trường hợp đó sau khi cuộc gọi đầu tiên được thực hiện. – Thomas

+0

@Thomas - đó là chính xác - xem câu trả lời của tôi.Tóm lại, nếu bạn muốn giữ câu lệnh sử dụng, bạn không muốn tiêm một cá thể đơn lẻ, mà thay vào đó là một phương thức nhà máy mà bạn có thể gọi để tạo ra bao nhiêu trường hợp tùy thích. – KeithS

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