即使无法构造对象,也会调用本地事件侦听器

时间:2011-08-02 13:57:01

标签: c# .net exception constructor event-handling

在对象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);
    }
}

1 个答案:

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