构造函数异常后引用不为空
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
属性
的来源
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
派生的,所以这发生在你抛出异常之前。
我有下面这行代码。
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
属性
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
派生的,所以这发生在你抛出异常之前。