在对象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);
}
}
答案 0 :(得分: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
字段。虽然它没有完全初始化,但在分配方面它仍然是一个完整的对象。