Почему параметр 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);
}