除非我在调试时扩展基础 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;
    }
}