Почему параметр out не разрешен в анонимном методе?

Это не обман Вызов метода с параметрами ref или out из анонимного метода

Мне интересно, почему почему параметры не разрешены в анонимных методах. Не разрешая мне параметры ref, но параметры out не так много.

что вы думаете об этом

Ответы

Ответ 1

В некотором роде это обман. Out являются параметрами ref. Для значения, используемого языком С#, есть дополнительный атрибут. Причина их запрещения - это то же самое, что и параметры ref.

Проблема здесь возникает из-за эффекта использования значения, объявленного вне анонимного метода в анонимном методе. Это приведет к захвату значения в лямбда и по необходимости произвольно продлевает срок его службы за пределы текущей функции. Это несовместимо с параметрами Out, которые имеют фиксированное время жизни.

Представьте, например, что параметр Out ссылался на локальную переменную в стеке. Лямбда может выполняться в любой произвольной точке в будущем и, следовательно, может выполняться, когда этот фрейм стека уже недействителен. Что означал бы параметр Out?

Ответ 2

Это в основном связано с тем, что параметры анонимного делегата/лямбда-выражения являются захваченными переменными, а захват переменных ref/out не имеет смысла в С#/CLR, поскольку для этого потребуется ref/out. Также обратите внимание, что я соединяю оба этих ключевых слова, потому что они фактически одинаковы.

Если вы хотите получить полное объяснение, Эрик Липперт подробно обсудил этот пункт дизайна в своем блоге. (См. Параграфы в нижней части в частности.)

Ответ 3

Единственное различие между параметрами out и ref заключается в том, что для параметра out будет применен токен [out]. Это то же самое, что и в CLR.

Чтобы реализовать его, компилятор должен будет генерировать поля ref, которые не поддерживаются.

Если вы подумаете об этом, вы поймете, что нет смысла разрешать анонимному методу использовать параметр out.

Каким будет следующий код?

static Func<object, object> Mess(out object param) {
    param = "Original";
    return i => param = i;
}
static Func<object, object> MessCaller() {
    object local;
    return Mess(out local);
}
static vouid Main() {
    Console.WriteLine(MessCaller()("New"));
    //The local variable that the lambda expression writes to doesn't exist anymore.
}

Ответ 4

Я столкнулся с этой загадкой при разработке кода обработки ошибок. Я хотел передать ссылку (выход) на сообщение об ошибке, которое будет регистрироваться. Это дало моим анонимным методам возможность выполнить несколько проверок, каждый из которых при необходимости установил сообщение об ошибке.

В конце концов я написал новую оболочку для анонимного метода, который работал по-другому. Но то, что, по моему мнению, может быть полезным для кого-то, заключается в том, что я мог просто сделать частный метод, который имел параметр out, и определил делегат, и сделал мой код этим. Надеюсь, что это помогает/вдохновляет кого-то.

    protected delegate void OutStringDelegate(int divider, out string errorText);
    protected void codeWrapper(int divider, OutStringDelegate del)
    {
        string ErrorMessage = "An Error Occurred.";

        try
        {
            del(divider, out ErrorMessage);
        }
        catch
        {
            LogError(ErrorMessage);
        }
    }
    public void UseWrapper(int input)
    {
        codeWrapper(input, codeToCall);
    }
    private int somePrivateValue = 0;
    private void codeToCall(int divider, out string errorMessage)
    {
        errorMessage = "Nice Error Message here!";
        somePrivateValue = 1 / divider; // call me with zero to cause error.
    }
    private void LogError(string msg)
    {
        Console.WriteLine(msg);
    }