C#Delegate值不在预期范围内

时间:2018-05-24 11:20:21

标签: c# unity3d input delegates event-handling

这是一个在Unity游戏引擎中编程C#的问题,但它可能是没有Unity经验的C#委托专家可以知道我做错了什么? (我确实已经在Unity论坛上发帖了。)

我试图传递一个在固定函数内调用的任意函数,它本身是通过AddListener事件的InputField.onEndEdit函数使用delegate关键字调用的。我是代表们的新手,但据我所知,我需要创建一个新的代表才能做到这一点,并且在阅读了一些仍然卡住的代表文章后,我有点纠结。目前,代码编译但出现ArgumentException错误。不幸的是,在Unity Editor中使用完整堆栈跟踪时,这就是我得到的所有堆栈跟踪:

ArgumentException: Value does not fall within the expected range.
CharacterController3D..ctor () (at Assets/Entities/DungeonCell/Priest/CharacterController3D.cs:95)

脚本名称为CharacterController3D.cs。此类中的第95行构造函数生成此错误:

Del marySuccess = question.MarySuccess;

结束目标:当玩家输入玩家在游戏中触发任意问题的答案时,ProcessAnswer函数将调用定制函数处理每个问题的正确答案,即每个问题将具有处理正确答案的不同函数响应。同样,如果玩家给出错误的答案等,ProcessAnswer函数将为该问题调用不同的自定义函数。

下面是ProcessAnswer函数,其中传递了任意委托delegate1,当给出正确答案时,在以下代码块中运行:

 private void ProcessAnswer (InputField input, string answer, float clockStart, Del delegate1)
 {
     if (String.Equals(answer, input.text.Trim(), StringComparison.OrdinalIgnoreCase)) // trim trailing spaces, accept any case in letters typed

     {
         countdownTimer.enabled = false; // stops timer
         float timePoints = Mathf.Round(2000/(clockStart - countdownTimer.TimeStoppedTenthsSecond()));
         delegate1();
     }
     else ....

上面的函数在同一个脚本中被调用:

 string answer = "grace";
 clockStart = 90f;
 inputField.onEndEdit.AddListener(delegate { ProcessAnswer(inputField, answer, clockStart, marySuccess); });

其中marySuccess是本例中的委托参数,由:

定义
 private delegate void Del();
 Del marySuccess = question.MarySuccess;

仍然在同一个脚本中,question这里被声明为同一对象上单独组件脚本的静态实例。我知道必须让代表静态参考它,无论如何都不能以非静态方式工作:

 private static Questions question;

并在Awake方法中初始化,所有脚本都在同一个脚本中:

 question = this.GetComponent<Questions>();

修改 作为评论,道歉错过了MarySuccess()方法代码本身,它与委托声明具有相同的签名(没有参数,返回void):

public void MarySuccess()
    {
        string phrase1 = "a";
        string phrase2 = "b";
        string phrase3 = "c";
        string phrase4 = "d";

        thoughtText.color = new Color(0.55f, 0f, 0.03f); // now matches (141,0,8) colour of input text, was Color.red;

        thoughtText.fontSize = 22;
        StartCoroutine(player.FillThoughtBox(phrase1, 3, phrase2, 3, phrase3, 5, phrase4));
        playerInputPanel.SetActive(false);

        player.Invoke("MaryHailed", 10f);
        Invoke("HideThoughtPanel", 22f);
    }

    // use Invoke() with desired delay, so that player can start moving and have more time to read the words before it disappears
    private void HideThoughtPanel()
    {
        thoughtButtonPanel.SetActive(false);
    }

EDIT2

我检查过public void MarySuccess () {}为空,仍然会出现相同的异常错误。

任何建议都非常感谢,谢谢!

2 个答案:

答案 0 :(得分:0)

我很久以前已经解决了这个问题,但是如果其他人阅读了,问题出在使用私有作用域作为委托函数。从上面的问题来看,我的代码是:

 private delegate void Del();
 Del marySuccess = question.MarySuccess;

在第二行产生了错误。应该是:

public delegate void Del();

因为MarySuccess()方法是公共方法,所以委托签名需要匹配它,并且也是公共的。实际上,由于这是在另一个类中调用方法,因此调用的方法必须是公共的才能工作,因此委托也必须是公共的,否则此处marySuccess的“值”不会“落入”预期范围”,即公共代表的“值”。我以为,由于Del()仅在此类中使用,因此它可以是私有的,但不知道将Del()用作数据类型和变量。我感到这是一个令人困惑的错误消息,因为我感觉正在为该委托类型分配一个引用而不是值,但是如果有经验的人可以在此分析中更正任何错误,则非常欢迎。

答案 1 :(得分:0)

在非常相似的情况下,我也遇到了同样的例外。以我为例,如果question.MarySuccess为null,则表达式question(获取委托)会引发此特别意外的错误。那是之间的区别

Del x = question.MarySuccess;

Del x = () => question.MarySuccess();

即使question为空,第二个版本也可以工作,并且仅在以后调用NullReferenceException并且仅在实际调用x时才引发{{1}}。