Ссылочный тип делегата - PullRequest
0 голосов
/ 03 сентября 2018

Почему эта программа показывает ошибку при использовании seq:

class Program
{
    delegate double Sequence(int r);

    void F(ref Sequence seq) // Here
    {
        Sequence seq2 = r =>
        {
            if (r % 2 == 0)
                return seq(r); // Here
            else
                return seq(2 * r); // Here
        };
        seq = seq2;
    }

    static void Main()
    {
    }
}

Ошибка CS1628 Невозможно использовать ref, out или параметр 'seq' внутри анонимный метод, лямбда-выражение, выражение запроса или локальный функция CsharpRefLambdaTest

Проблема в том, что параметр seq является ссылочным типом. Но почему это не так? В чем проблема со ссылкой seq? Если seq не является ссылкой, в программе нет ошибок.

Есть ли способ исправить программу, сохранив в качестве справки seq?

Программа просто тестовая и ничего не собирается делать.

================

Мне нужно использовать значение seq, чтобы определить новую последовательность seq2, а затем назначить seq = seq2. Но значения seq не могут быть использованы. Если значения seq не пригодны для использования, почему C # вообще позволяет seq быть ссылкой?

===============================

Edit:

Приведенная выше программа является просто упрощенной версией следующего:

class Program
{
    delegate double Sequence(int r);

    Sequence G(Sequence seq)
    {
        Sequence seq2 = r =>
        {
            if (r % 2 == 0)
                return seq(r);
            else
                return seq(2 * r);
        };
        return seq2;
    }

    void F(ref Sequence seq)
    {
        seq = G(seq);
    }

    static void Main()
    {
    }
}

Но я не понимаю, почему я не могу удалить G и вместо этого добавить определяющий код G inside F`.

1 Ответ

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

здесь появляется сообщение об ошибке: «CS1628 Невозможно использовать ref, out или в параметре 'seq' внутри анонимного метода, лямбда-выражения, выражения запроса или локальной функции» - seq2 - это лямбда-выражение; это не имеет ничего общего с ссылочными типами, а скорее: время жизни. Вы могли бы, в конце концов, назвать это как:

void Foo() {
    Sequence bar = SomeMethod; // bar is a LOCAL of Foo
    F(ref bar);
    // not shown: perhaps do something with bar, perhaps not
}

В этот момент F потребуется каким-то образом создать лямбду, содержащую в себе ссылку на позицию в стеке (ссылку на локальный bar). Теперь обратите внимание, что эта лямбда, будучи объектом, может пережить Foo, а bar будет неопределенным - и, возможно, многократно используемым - местом в памяти.

Итак: вы не можете «захватить» параметры, которые передаются как ref, in наш out, где я использую здесь «захват» свободно, чтобы означать «использование в рамках лямбды или анонимный метод, который формирует дерево выражений, выражение делегата или внутри блока итератора или асинхронного продолжения ".

Просто удалите ref. Вам это не нужно, и это не помогает. Если вы намереваетесь изменить делегата, то вместо этого рассмотрите возврат составного делегата.


в качестве альтернативы: снимите значение и сделайте снимок:

void F(ref Sequence seq)
{
    var tmp = seq;
    seq = r =>
    {
        if (r % 2 == 0)
            return tmp(r);
        else
            return tmp(2 * r);
    };
}

это позволяет избежать проблемного сценария, поскольку снимок разыменовывает параметр ref, что означает: теперь нет никакой возможности захватить расположение стека.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...