2011-08-02 12 views
8

W konstruktorze obiektu, Listener, pobieramy argument i subskrybujemy jedno z jego zdarzeń. Jeśli wyjątek zostanie zgłoszony w konstruktorze po zasubskrybowaniu zdarzenia, metoda zostanie wywołana, gdy zdarzenie zostanie wywołane - nawet jeśli obiekt nie został pomyślnie skonstruowany i, o ile mi wiadomo, żadne wystąpienie nie istnieje.Lokalny detektor zdarzeń wywołany, mimo że obiekt nie został skonstruowany

Teraz mogę to naprawić, oczywiście nieznacznie zmieniając projekt, jednak bardziej interesuje mnie, dlaczego metoda instancji jest wywoływana, mimo że konstruktor nie zakończył się pomyślnie? Jeśli metoda używa dowolnych zmiennych lokalnych, które nie zostały zainicjowane przed wyjątkiem, to oczywiście przechodzi w 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); 
    } 
} 

Odpowiedz

6

rzucając wyjątek od konstruktora oznacza wystąpienie może ewentualnie zakończyć się niekompletna, takie postępowanie nie zatrzymuje sam przypadek ze tworzone i przechowywane w pamięci (jak dzieje przed jego konstruktor nazywa się).

Co więcej, obsługa zdarzenia była już związana z czasem, w którym rzucisz wyjątek, więc podniesienie zdarzenia spowoduje wywołanie programu obsługi.

Aby szybko ilustrują pierwszy punkt, jeśli dał Listener pole do zainicjowania w jej konstruktora, a następnie próbował go zainicjować po wyrzuceniu wyjątku (co oczywiście nie będzie działać):

string foo; 

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

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

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

a następnie próbował uzyskać dostęp do swojego OnSomethingChanged handler:

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

Niezależnie od tego, jak się nazywają new Listener(...) wyjście byłoby

 
Listener.foo = 

po prostu dlatego, że słuchacz nie miał możliwości zainicjowania swojego pola foo. Mimo że nie został w pełni zainicjowany, jest nadal kompletnym obiektem pod względem alokacji.

+0

To naprawdę niezwykle interesujące i nie to, czego się spodziewałem. Znalazłem również [ten post] (http://stackoverflow.com/questions/5697446/is-an-object-constructed-if-an-initializer- throws) jako dość interesujący. Dziękujemy za odpowiedź –

+0

Nie ma za co. Ten post dotyka zupełnie innej sprawy, ale istnieje podobna przesłanka. – BoltClock

Powiązane problemy