2011-08-02 33 views
8

Trong hàm tạo của một đối tượng, Listener, chúng ta lấy một đối số và đăng ký một trong các sự kiện của nó. Nếu một ngoại lệ được ném vào bên trong hàm tạo sau khi sự kiện được đăng ký, phương thức OnSomethingChanged() vẫn được gọi khi sự kiện được nâng lên - thậm chí thông qua đối tượng không được xây dựng thành công và theo như tôi biết, không có cá thể nào tồn tại.Trình nghe sự kiện cục bộ được gọi ngay cả khi đối tượng không được xây dựng

Bây giờ tôi có thể khắc phục điều này bằng cách hiển thị lại thiết kế một chút, tuy nhiên tôi quan tâm nhiều hơn lý do tại sao một phương thức thể hiện được gọi mặc dù hàm tạo không hoàn tất thành công? Nếu phương thức này sử dụng bất kỳ biến cục bộ nào chưa được khởi tạo trước khi ngoại lệ thì rõ ràng là nó đi BOOM!

class Program 
{ 
    static void Main(string[] args) 
    { 
     Input input = new Input(); 

     try 
     { 
      new Listener(input); 
     } 
     catch (InvalidOperationException) 
     { 
      // swallow 
     } 

     input.ChangeSomething(); // prints "Something changed!" 
    } 
} 

public class Listener 
{ 
    public Listener(Input input) 
    { 
     input.SomethingChanged += OnSomethingChanged; // subscibe 

     throw new InvalidOperationException(); // do not let constructor succeed 
    } 

    void OnSomethingChanged(object sender, EventArgs e) 
    { 
     Console.WriteLine("Something changed!"); 
    } 
} 

public class Input 
{ 
    public event EventHandler SomethingChanged; 

    public void ChangeSomething() 
    { 
     SomethingChanged(this, EventArgs.Empty); 
    } 
} 

Trả lời

6

Trong khi ném một ngoại lệ từ một constructor có nghĩa là một ví dụ có thể có khả năng kết thúc trong tình trạng không đầy đủ, làm như vậy không chỉ dừng lại các trường hợp riêng của mình từ được tạo ra và lưu trữ trong bộ nhớ (như điều đó xảy ra trước của nó constructor được gọi).

Hơn nữa, trình xử lý sự kiện đã bị ràng buộc bởi thời gian bạn ném ngoại lệ, vì vậy việc tăng sự kiện sẽ khiến trình xử lý được gọi.

Để nhanh chóng minh họa điểm đầu tiên, nếu bạn đã Listener một lĩnh vực để khởi tạo trong constructor của nó, sau đó cố gắng để khởi tạo nó sau khi ném ngoại lệ (mà rõ ràng là sẽ không làm việc):

string foo; 

    public Listener(Input input, string f) 
    { 
     input.SomethingChanged += OnSomethingChanged; 

     // Because this is thrown... 
     throw new InvalidOperationException(); 

     // ... this never happens 
     foo = f; 
    } 

và sau đó cố gắng truy cập vào nó trong OnSomethingChanged xử lý của nó:

void OnSomethingChanged(object sender, EventArgs e) 
    { 
     Console.WriteLine("Listener.foo = " + foo); 
    } 

Bất kể thế nào bạn gọi new Listener(...), sản lượng sẽ là

 
Listener.foo = 

đơn giản chỉ vì người nghe không có cơ hội khởi tạo trường foo của mình. Mặc dù nó không được khởi tạo hoàn toàn, nhưng nó vẫn là một đối tượng hoàn chỉnh về mặt phân bổ.

+0

Điều đó thực sự cực kỳ thú vị và không phải những gì tôi mong đợi. Tôi cũng đã tìm thấy [bài đăng này] (http://stackoverflow.com/questions/5697446/is-an-object-constructed-if-an-initializer-throws) là khá nhiều thông tin. Cảm ơn bạn đã trả lời –

+0

Bạn được chào đón. Bài đăng đó liên quan đến một vấn đề hoàn toàn khác, nhưng một tiền đề tương tự là ở đó. – BoltClock

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