Значение делегата C # не попадает в ожидаемую ошибку диапазона - PullRequest
0 голосов
/ 24 мая 2018

это вопрос программирования C # в игровом движке Unity, но это может быть эксперт-делегат C # без опыта Unity, может знать, что я делаю неправильно?(Я уже писал на форуме Unity).

Я пытаюсь передать произвольную функцию для вызова внутри фиксированной функции, которая сама вызывается с использованием ключевого слова делегата через функцию AddListener события InputField.onEndEdit,Я новичок в делегатах, но, как я понимаю, мне нужно создать нового делегата, чтобы сделать это, и я немного запутался, прочитав несколько статей о делегатах, которые все еще застряли.В настоящее время код компилируется, но появляется ошибка 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>();

EDIT В качестве комментариев извинения за отсутствие самого кода метода 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);
    }

РЕДАКТИРОВАТЬ2

Я проверил даже с public void MarySuccess () {} пусто, все равно выдает ту же ошибку исключения.

Любые предложения очень благодарны, спасибо!

Ответы [ 2 ]

0 голосов
/ 16 апреля 2019

Я получил то же исключение в очень похожем случае.В моем случае оказалось, что выражение question.MarySuccess (выборка делегата) вызывает эту особенно неожиданную ошибку, если question равно нулю.В этом разница между

Del x = question.MarySuccess;

и

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

Вторая версия будет работать, даже если question равно нулю, и поднимать NullReferenceException только позже и только если xна самом деле называется.

0 голосов
/ 17 сентября 2018

Я исправил это давным-давно, но в случае, если кто-то еще читает, проблема заключалась в использовании частного контекста для функции делегата.Из вышеприведенного вопроса код, который у меня был:

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

, вызвал ошибку во 2-й строке.Оно должно быть:

public delegate void Del();

, поскольку метод MarySuccess() является открытым методом, подпись делегата должна соответствовать ему, а также быть публичной.Действительно, так как это вызывало метод в другом классе, вызываемый метод должен был бы быть открытым для работы, и поэтому делегат также должен быть открытым, в противном случае «значение» marySuccess здесь «не попадает в ожидаемое значение».диапазон 'т.е. открытый делегат' значение '.Я думал, что поскольку Del() используется только в этом классе, он может быть закрытым, но я не ценю, что Del() используется как тип данных, а также как переменная.Это сбивающее с толку сообщение об ошибке, так как я чувствую, что типу делегата присваивается ссылка, а не значение, но очень желательно, если кто-то более опытный может исправить любые ошибки в деталях этого анализа.

...