Почему выходной параметр не разрешен в анонимном методе?
-
08-07-2019 - |
Вопрос
Это не обман Вызов метода с параметрами ref или out из анонимного метода
Мне интересно, что почему параметры не разрешены в анонимных методах. Отказ от использования параметров ref имеет для меня немного больше смысла, но для параметров out не так много. Р>
что вы думаете об этом
Решение
В некотором смысле это обман. Параметры Out
являются параметрами ref
. У значения просто есть дополнительный атрибут, который используется языком C #. Причина их запрета в точности совпадает с параметрами ref
.
Проблема здесь возникает в результате использования значения, объявленного вне анонимного метода в анонимном методе. Это позволит зафиксировать значение в лямбде и по необходимости произвольно продлить срок его службы за пределы текущей функции. Это несовместимо с параметрами out
, которые имеют фиксированное время жизни. Р>
Представьте, например, что параметр out
ссылается на локальную переменную в стеке. Лямбда может выполняться в любой произвольной точке в будущем и, следовательно, может выполняться, когда этот кадр стека больше не действителен. Что тогда будет означать параметр out
?
Другие советы
Это в основном связано с тем фактом, что параметры анонимного делегата / лямбда-выражений являются захваченными переменными , и захватом ref
/ out
Переменные не имеют никакого смысла в C # / CLR, так как для этого потребуются внутренние ref
/ out
fields . Также обратите внимание, что я связываю оба этих ключевых слова, потому что они фактически одинаковы.
Если вы хотите получить полное объяснение, Эрик Липперт подробно обсудил этот вопрос в своем блоге . (См. Параграфы в нижней части, в частности.)
Единственное различие между параметрами 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.
}
Я столкнулся с этой загадкой при разработке кода обработки ошибок. Я хотел передать ссылку (out) на сообщение об ошибке, которое будет зарегистрировано. Это дало моим анонимным методам возможность выполнить несколько проверок, каждая из которых при необходимости установила сообщение об ошибке. Р>
Я закончил тем, что написал новую оболочку для анонимного метода, который работал по-другому. Но я подумал, что для кого-то это может иметь какое-то значение, так как я мог просто создать приватный метод с параметром 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);
}