构造函数异常后引用不为空

Reference Not Null After Constructor Exception

我有下面这行代码。

Application.Current.MainWindow = new MainWindow();

将构造函数放在调试器告诉我的行上 Application.Current.MainWindow 为空。 然后构造函数抛出异常。在 catch 块中,Application.Current.MainWindow 不再为空。 Application.Current.MainWindow的值不应该被修改,但它是。

如果我改为:

Window w = new MainWindow();

如预期抛出异常后w为null

我错过了什么?

更新

只需调用 class 的构造函数,subclasses Window 会导致 Application.Current.MainWindow 更改为指向该实例。即使构造函数抛出异常,也会发生这种情况。这会使应用程序处于不一致状态。

例如,它会让我调用 Application.Current.MainWindow.Show,这会产生各种问题,因为 Window 的状态无效。

查看 Application.MainWindow 属性

的来源

来源:http://referencesource.microsoft.com/#PresentationFramework/Framework/System/Windows/Application.cs,cf9c51e402f97b05

public Window MainWindow
{
    get
    {
        VerifyAccess();
        return _mainWindow;
    }

    set
    {
        VerifyAccess();

        //
        // Throw if an attempt is made to change RBW.
        // or we are browser hosted, main window is null, and attempt is made to change RBW.
        //
        if ( ( _mainWindow is RootBrowserWindow )
                ||
            ((BrowserCallbackServices != null ) &&
                ( _mainWindow == null ) &&
                ( !( value is RootBrowserWindow ))) )
        {
            throw new InvalidOperationException( SR.Get( SRID.CannotChangeMainWindowInBrowser ) ) ;
        }

        if (value != _mainWindow)
        {
            _mainWindow = value;
        }
    }
}

这是一个值得关注的问题。另一点是其他线程或框架本身可以将其设置在其他地方。查看此评论

By default - MainWindow will be set to the first window opened in the application. However the MainWindow may be set programmatically to indicate "this is my main window". It is a recommended programming style to refer to MainWindow in code instead of Windows[0].

在构造函数完成之前,运行时无法设置对已分配内存的引用。它可能是作为一种优化来完成的,但只能使用特定于框架的 类,例如 System.String.

编辑:查看Window.Initialize方法

private void Initialize()
{
    // AVTempUIPermission avtUIPermission = new AVTempUIPermission(AVTUIPermissionNewWindow.LaunchNewWindows);
    // CASRemoval:avtUIPermission.Demand();

    //  this makes MeasureCore / ArrangeCore to defer to direct MeasureOverride and ArrangeOverride calls
    //  without reading Width / Height properties and modifying input constraint size parameter...
    BypassLayoutPolicies = true;

    // check if within an app && on the same thread
    if (IsInsideApp == true)
    {
        if (Application.Current.Dispatcher.Thread == Dispatcher.CurrentDispatcher.Thread)
        {
            // add to window collection
            // use internal version since we want to update the underlying collection
            App.WindowsInternal.Add(this);
            if (App.MainWindow == null)
            {
                App.MainWindow = this;
            }
        }
        else
        {
            App.NonAppWindowsInternal.Add(this);
        }
    }
}

具体在行:

App.WindowsInternal.Add(this);
if (App.MainWindow == null)
{
    App.MainWindow = this;
}

这是设置 Window 属性 的地方。因为你的 MainWindow 是从 Window 派生的,所以这发生在你抛出异常之前。