【问题标题】:Reference Not Null After Constructor Exception构造函数异常后引用不为空
【发布时间】:2015-03-04 05:16:21
【问题描述】:

我有以下代码行。

Application.Current.MainWindow = new MainWindow();

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

如果我这样做:

Window w = new MainWindow();

按预期抛出异常后,w为null。

我错过了什么?

更新

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

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

【问题讨论】:

    标签: c# wpf constructor


    【解决方案1】:

    查看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;
            }
        }
    }
    

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

    默认情况下 - MainWindow 将设置为应用程序中打开的第一个窗口。 但是,可以通过编程方式设置 MainWindow 以指示“这是我的主窗口”。 推荐的编程风格是在代码中引用 MainWindow 而不是 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 派生的,所以这发生在你抛出异常之前。

    【讨论】:

    • getter 不应该被调用。我通过调用以下方法排除了二传手是罪魁祸首:MainWindow = null。正如预期的那样,它仍然为空。
    • 应用程序不打开任何窗口。 XAML 中未指定主窗口。
    • MainWindow 在您第一次尝试实例化窗口时似乎确实被设置了。即使失败了。
    • @denver,我找到了问题的根源并更新了答案。
    • @denver,我不确定。理想的方法是捕获异常,处理它并尝试再次设置MainWindow,这样这次你的构造函数就不会抛出异常。并且您绝对应该将可能失败的代码移到构造函数之外以避免这种情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 1970-01-01
    相关资源
    最近更新 更多