【问题标题】:Local event listener called even though object failed to be constructed即使无法构造对象,也会调用本地事件侦听器
【发布时间】:2011-08-02 13:57:00
【问题描述】:

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

现在我可以通过稍微重构设计来解决这个问题,但是我更感兴趣的是为什么即使构造函数没有成功完成也会调用实例方法?如果该方法使用了在异常之前尚未初始化的任何局部变量,那么显然它会爆炸!

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);
    }
}

【问题讨论】:

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


    【解决方案1】:

    虽然从构造函数中抛出异常意味着实例可能最终处于不完整状态,但这样做并不会阻止实例本身被创建并存储在内存中(因为发生这种情况之前它的构造函数被调用)。

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

    为了快速说明第一点,如果您在其构造函数中给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(...),输出都是

    听众.foo =

    仅仅是因为侦听器没有机会初始化其foo 字段。虽然它没有完全初始化,但在分配方面它仍然是一个完整的对象。

    【讨论】:

    • 这确实非常有趣,不是我所期望的。我还发现this post 信息量很大。感谢您的回复
    • 不客气。那篇文章涉及完全不同的问题,但存在类似的前提。
    猜你喜欢
    • 1970-01-01
    • 2017-01-31
    • 2016-10-19
    • 2019-12-02
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多