2011-08-02 153 views
8

在对象的构造函数Listener中,我们接受一个参数并订阅其中一个事件。如果事件订阅后在构造函数中引发异常,则在引发事件时仍会调用OnSomethingChanged()方法 - 即使通过该对象未成功构建,并且据我所知,也不存在实例。即使对象构建失败也会调用本地事件侦听器

现在我可以通过明显重新设计这个设计来解决这个问题,但是我更感兴趣的是为什么实例方法被调用,即使构造函数没有成功完成?如果该方法使用任何在异常之前未初始化的局部变量,那么显然它会进入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); 
    } 
} 

回答

6

虽然从一个构造抛出异常是指例如可潜在最终在不完全的状态,这样做不会被创建和(存储在存储器中停止实例本身为之前发生其构造函数被调用)。

此外,事件处理函数在抛出异常时已经被绑定,因此引发该事件将导致处理程序被调用。

要快速说明第一点,如果你给一个Listener场在其构造函数初始化,然后试图抛出异常后(这显然是行不通的)来初始化它:

string foo; 

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

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

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

然后尝试访问在其OnSomethingChanged处理程序:

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

不管你怎么称呼new Listener(...),输出会

 
Listener.foo = 

只是因为听众没有机会初始化其foo字段。尽管它没有完全初始化,但它仍然是一个完整的分配对象。

+0

这确实非常有趣,而不是我所期望的。我也发现[这篇文章](http://stackoverflow.com/questions/5697446/is-an-object-constructed-if-an-initializer-throws)是相当丰富的。感谢您的回复 –

+0

不客气。这篇文章完全涉及了另一个问题,但也有类似的前提。 – BoltClock

相关问题