除非我在调试时扩展基础 class 对象,否则获取 NullReferenceException
Getting NullReferenceException unless I expand base class object while debugging
首先,我使用的是 Xamarin Studio 6.1.3 以防万一。
我正在创建一个简单的应用程序并希望登录表单显示为 sheet。我按照 Xamarin 教程创建了 sheets (https://developer.xamarin.com/guides/mac/user-interface/working-with-dialogs/#Creating_a_Custom_Sheet),但 运行 遇到了问题。
根据教程,我创建了一个 class:
using System;
using Foundation;
using AppKit;
namespace SampleProject
{
public partial class UserLoginController : NSViewController
{
private NSViewController _presentor;
public string Username
{
get { return TxtUsername.StringValue; }
set { TxtUsername.StringValue = value; }
}
public string Password
{
get { return TxtPassword.StringValue; }
set { TxtPassword.StringValue = value; }
}
public NSViewController Presentor
{
get { return _presentor; }
set { _presentor = value; }
}
public UserLoginController(IntPtr handle) : base(handle)
{
}
private void CloseDialog()
{
Presentor.DismissViewController(this);
}
partial void BtnCancelClick(NSObject sender)
{
RaiseDialogCanceled();
CloseDialog();
}
partial void BtnLoginClick(NSObject sender)
{
RaiseDialogAccepted();
CloseDialog();
}
public EventHandler DialogAccepted;
internal void RaiseDialogAccepted()
{
if (this.DialogAccepted != null)
this.DialogAccepted(this, EventArgs.Empty);
}
public EventHandler DialogCanceled;
internal void RaiseDialogCanceled()
{
if (this.DialogCanceled != null)
this.DialogCanceled(this, EventArgs.Empty);
}
}
}
并且我在我的 ViewController class:
中添加了 PrepareForSegue 覆盖
public override void PrepareForSegue(NSStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue(segue, sender);
switch (segue.Identifier)
{
case "UserLoginSegue":
UserLoginController loginSheet = segue.DestinationController as UserLoginController;
loginSheet.Username = ""; //This line throws NullReferenceException unless I set a breakpoint and expand loginSheet.Base before allowing this line to execute.
loginSheet.Password = "";
loginSheet.Presentor = this;
loginSheet.DialogAccepted += (object s, EventArgs e) => { Console.WriteLine("OK Clicked"); };
loginSheet.DialogCanceled += (object s, EventArgs e) => { Console.WriteLine("Cancel Clicked"); };
break;
}
}
查看上面代码块中的注释。我基本上在该行上设置了一个断点,当它触发时,我检查 loginSheet 对象。如果我展开 Base 对象来检查它然后继续执行,一切都会按预期进行。如果我不这样做,每当代码尝试访问 UserLoginController class.
中的任何 fields/properties/methods 时,我都会收到 NullReferenceException
我完全不明白为什么会这样。我在 UserLoginController 的构造函数中设置了一个断点,并验证了它是使用句柄调用的,并且也应该调用基本构造函数。
我已经通读了本教程好几遍,没有发现我遗漏的任何内容。似乎找不到其他人遇到同样的问题。
我的最终问题是:如何使代码按预期工作?
为了学习(这可能会阐明问题):当我在调试时检查我的 UserLoginController class 的基对象时,幕后发生了什么?
当您在调试器中展开一个对象时,所有未标记特定属性的属性都会通过反射读取,以便我们可以在 IDE.
中显示它们
也许这些属性之一有副作用?您应该能够使用反射重现效果,然后将 属性 列表一分为二以查看谁在影响您的行为。
解决方案原来是我需要检查我的 UserLoginController
.
的 View
属性
我添加了以下行:
var theView = loginSheet.View;
一切都按预期进行。我还没有深入研究 View
属性 以了解它在幕后做了什么使一切正常。
这是修改后的有效 PrepareForSegue
覆盖方法:
public override void PrepareForSegue(NSStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue(segue, sender);
switch (segue.Identifier)
{
case "UserLoginSegue":
UserLoginController loginSheet = segue.DestinationController as UserLoginController;
var theView = loginSheet.View;
loginSheet.Username = "";
loginSheet.Password = "";
loginSheet.Presentor = this;
loginSheet.DialogAccepted += (object s, EventArgs e) => { Console.WriteLine("OK Clicked"); };
loginSheet.DialogCanceled += (object s, EventArgs e) => { Console.WriteLine("Cancel Clicked"); };
break;
}
}
首先,我使用的是 Xamarin Studio 6.1.3 以防万一。
我正在创建一个简单的应用程序并希望登录表单显示为 sheet。我按照 Xamarin 教程创建了 sheets (https://developer.xamarin.com/guides/mac/user-interface/working-with-dialogs/#Creating_a_Custom_Sheet),但 运行 遇到了问题。
根据教程,我创建了一个 class:
using System;
using Foundation;
using AppKit;
namespace SampleProject
{
public partial class UserLoginController : NSViewController
{
private NSViewController _presentor;
public string Username
{
get { return TxtUsername.StringValue; }
set { TxtUsername.StringValue = value; }
}
public string Password
{
get { return TxtPassword.StringValue; }
set { TxtPassword.StringValue = value; }
}
public NSViewController Presentor
{
get { return _presentor; }
set { _presentor = value; }
}
public UserLoginController(IntPtr handle) : base(handle)
{
}
private void CloseDialog()
{
Presentor.DismissViewController(this);
}
partial void BtnCancelClick(NSObject sender)
{
RaiseDialogCanceled();
CloseDialog();
}
partial void BtnLoginClick(NSObject sender)
{
RaiseDialogAccepted();
CloseDialog();
}
public EventHandler DialogAccepted;
internal void RaiseDialogAccepted()
{
if (this.DialogAccepted != null)
this.DialogAccepted(this, EventArgs.Empty);
}
public EventHandler DialogCanceled;
internal void RaiseDialogCanceled()
{
if (this.DialogCanceled != null)
this.DialogCanceled(this, EventArgs.Empty);
}
}
}
并且我在我的 ViewController class:
中添加了 PrepareForSegue 覆盖 public override void PrepareForSegue(NSStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue(segue, sender);
switch (segue.Identifier)
{
case "UserLoginSegue":
UserLoginController loginSheet = segue.DestinationController as UserLoginController;
loginSheet.Username = ""; //This line throws NullReferenceException unless I set a breakpoint and expand loginSheet.Base before allowing this line to execute.
loginSheet.Password = "";
loginSheet.Presentor = this;
loginSheet.DialogAccepted += (object s, EventArgs e) => { Console.WriteLine("OK Clicked"); };
loginSheet.DialogCanceled += (object s, EventArgs e) => { Console.WriteLine("Cancel Clicked"); };
break;
}
}
查看上面代码块中的注释。我基本上在该行上设置了一个断点,当它触发时,我检查 loginSheet 对象。如果我展开 Base 对象来检查它然后继续执行,一切都会按预期进行。如果我不这样做,每当代码尝试访问 UserLoginController class.
中的任何 fields/properties/methods 时,我都会收到 NullReferenceException我完全不明白为什么会这样。我在 UserLoginController 的构造函数中设置了一个断点,并验证了它是使用句柄调用的,并且也应该调用基本构造函数。
我已经通读了本教程好几遍,没有发现我遗漏的任何内容。似乎找不到其他人遇到同样的问题。
我的最终问题是:如何使代码按预期工作?
为了学习(这可能会阐明问题):当我在调试时检查我的 UserLoginController class 的基对象时,幕后发生了什么?
当您在调试器中展开一个对象时,所有未标记特定属性的属性都会通过反射读取,以便我们可以在 IDE.
中显示它们也许这些属性之一有副作用?您应该能够使用反射重现效果,然后将 属性 列表一分为二以查看谁在影响您的行为。
解决方案原来是我需要检查我的 UserLoginController
.
View
属性
我添加了以下行:
var theView = loginSheet.View;
一切都按预期进行。我还没有深入研究 View
属性 以了解它在幕后做了什么使一切正常。
这是修改后的有效 PrepareForSegue
覆盖方法:
public override void PrepareForSegue(NSStoryboardSegue segue, NSObject sender)
{
base.PrepareForSegue(segue, sender);
switch (segue.Identifier)
{
case "UserLoginSegue":
UserLoginController loginSheet = segue.DestinationController as UserLoginController;
var theView = loginSheet.View;
loginSheet.Username = "";
loginSheet.Password = "";
loginSheet.Presentor = this;
loginSheet.DialogAccepted += (object s, EventArgs e) => { Console.WriteLine("OK Clicked"); };
loginSheet.DialogCanceled += (object s, EventArgs e) => { Console.WriteLine("Cancel Clicked"); };
break;
}
}