2016-12-22 18 views
6

Tôi có một trình bao bọc đơn giản cho bộ chứa Unity IoC (sử dụng tạm thời Dịch vụ định vị [chống] Mô hình giới thiệu DI cho một mã số cũ) và từ IUnityContainer trong Unity thực hiện IDisposable I muốn phơi bày điều đó thông qua trình bao bọc.Tràn ngăn xếp khi loại bỏ tài nguyên được quản lý

Các wrapper đơn giản là đủ:

public class IoCContainer : IIoCContainer 
{ 
    private IUnityContainer _container; 

    public IoCContainer(IUnityContainer container) 
    { 
     _container = container; 
    } 

    public T Resolve<T>() 
    { 
     return _container.Resolve<T>(); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    ~IoCContainer() 
    { 
     Dispose(false); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
      if (_container != null) 
      { 
       _container.Dispose(); 
       _container = null; 
      } 
    } 
} 

IIoCContainer là giao diện miền mà không có gì nhưng T Resolve<T>() vào nó, và tất nhiên IDisposable. Vì vậy, mọi thứ bên dưới rằng một phương pháp đơn giản là việc triển khai IDisposableas I found it on MSDN.

Tuy nhiên, khi .Dispose() được gọi trên đối tượng này (chẳng hạn như khi thoát khỏi khối using), hãy tăng số StackOverflowException. Gỡ lỗi, có vẻ như các cuộc gọi stack lặp đi lặp lại giữa:

  • Dispose() được gọi vào lớp này
  • nào gọi Dispose(true) trên lớp này
  • nào gọi Dispose() trên IUnityContainer
  • nào gọi Dispose() trên lớp này

enter image description here

tôi có thể giải quyết này trong trường hợp này bằng cách đặt một lá cờ bool trên lớp, đặt nó trên dòng đầu tiên của Dispose(), và kiểm tra nó trong Dispose(bool), vì vậy đệ quy kết thúc vào lần lặp thứ hai của mình. Nhưng tại sao điều này lại xảy ra ngay từ đầu? Tôi chỉ có thể giả định rằng tôi đã bỏ lỡ điều gì đó hiển nhiên hoặc hiểu nhầm điều gì đó về việc xử lý tài nguyên. Nhưng cái gì?

+4

bạn đã thêm 'IIoCContainer' vào vùng chứa thống nhất chưa? – Rhumborl

+1

Đây có thể là một câu hỏi ngớ ngẩn, nhưng là 'this' và' _container' cùng một đối tượng? – adv12

+0

@Rhumborl: Tôi nghĩ rằng đó có thể là vấn đề, bây giờ bạn chỉ ra. Các quy ước được sử dụng khi đăng ký bao gồm các hội đồng có chứa điều này rất thực hiện. Vì vậy, có lẽ 'UnityContainer' đang giữ một tham chiếu đến một' IoCContainer' đã giải quyết và đang xử lý nó? Tôi sẽ kiểm tra và xem những gì tôi có thể tìm thấy. Tôi không thể nghĩ một cách rõ ràng về một trường hợp mà tôi cần phải * giải quyết * một trường hợp của vùng chứa này, vì vậy có thể an toàn để loại trừ nó khỏi đăng ký. – David

Trả lời

4

Đây là thực hiện IDisposable trong UnityContainer. Rõ ràng là bạn không thể vứt bỏ thùng chứa mẹ của bạn. Nó sẽ lặp qua tất cả các đăng ký và xử lý chúng nếu chúng cũng là IDisposable.Hãy xem:

protected virtual void Dispose(bool disposing) 
{ 
    if (disposing) 
    { 
     if (lifetimeContainer != null) 
     { 
      lifetimeContainer.Dispose(); 
      lifetimeContainer = null; 

      if (parent != null && parent.lifetimeContainer != null) 
      { 
       parent.lifetimeContainer.Remove(this); 
      } 
     } 

     extensions.OfType<IDisposable>().ForEach(ex => ex.Dispose()); 
     extensions.Clear(); 
    } 
} 
+1

Thật vậy, như được khám phá cũng như thông qua các bình luận về câu hỏi, cá thể 'UnityContainer' đang giữ một tham chiếu đến một' IoCContainer' đã được giải quyết. Vì vậy, 'ForEach() 'cuối cùng là nguồn gốc của đệ quy. Tôi đã gỡ bỏ 'IoCContainer' khỏi cấu hình Unity, vì tôi không thể nghĩ ra một lý do tại sao nó sẽ cần phải giải quyết một thể hiện của chính nó. Cảm ơn! – David

1

Tôi tin rằng vấn đề ở đây là bạn không phải xử lý trường hợp vùng chứa triển khai IUnityContainer trong lớp học của bạn.

Ví dụ này đang được chuyển thành tài nguyên cho lớp của bạn, nhưng nó được tạo ra bên ngoài, vì vậy bất kỳ mã nào tạo ra cá thể đó là trường hợp phải chịu trách nhiệm xử lý đúng.

IoCContainer của bạn chỉ nên quan tâm đến việc xử lý tài nguyên mà nó tạo ra trong nội bộ.

+3

Không có bối cảnh khác tôi đồng ý. Tuy nhiên, trong trường hợp này đối tượng này "sở hữu" tài nguyên này. Tài nguyên đã được cung cấp cho nó bởi một hàm khởi tạo tĩnh để đăng ký 'UnityContainer', kết thúc nó trong lớp này và trả về cho người gọi. – David

+0

Bất kỳ ai tạo tài nguyên đều sở hữu nó, không phải ai sử dụng nó, @David. Đó là toàn bộ điểm sử dụng một container IoC. Nó là container quản lý vòng đời (và xử lý) của các đối tượng mà nó tạo ra. – JuanR

+0

Hãy để tôi làm rõ, bất cứ ai tạo ra cá thể IUnityContainer được chuyển đến trình bao bọc trong mã của bạn phải là người để vứt bỏ nó tại một thời điểm nào đó. – JuanR

1

Đây không phải là câu trả lời tốt nhất có thể, nhưng nếu bạn không có controll qua việc thực hiện các IUnityContainer và nó để xử lý IoCContainer bạn luôn có thể phá vỡ các chuỗi recurrection trong ít nhất hai, cách hợp lệ:

protected virtual void Dispose(bool disposing) 
{ 
    if (disposing) 
     if (_container != null) 
     { 
      var tempContainer = _container; 
      _container = null; 
      tempContainer.Dispose(); 
     } 
} 

hoặc

private bool isDisposed = false; 
protected virtual void Dispose(bool disposing) 
{ 
    if(isDisposed) return; 
    isDisposed = true; 

    if (disposing) 
     if (_container != null) 
     { 
      _container.Dispose(); 
      _container = null; 
     } 
} 
Các vấn đề liên quan