Возвращаемые значения почти всегда правильный выбор, когда у метода больше нечего возвращать. (На самом деле, я не могу вспомнить ни одного случая, когда я бы когда-либо хотел бы метод void с параметром out
, если бы у меня был выбор. Deconstruct
методы C # 7 для поддерживаемых языков деконструкция действует как очень, очень редкое исключение из этого правила.)
Помимо всего прочего, он не позволяет вызывающей стороне объявлять переменную отдельно:
int foo;
GetValue(out foo);
против
int foo = GetValue();
Значения Out также предотвращают сцепление метода следующим образом:
Console.WriteLine(GetValue().ToString("g"));
(Действительно, это также одна из проблем с установщиками свойств, и поэтому в шаблоне компоновщика используются методы, которые возвращают компоновщик, например, myStringBuilder.Append(xxx).Append(yyy)
.)
Кроме того, параметры вывода немного сложнее использовать с отражением и обычно также усложняют тестирование. (Обычно делается больше усилий для упрощения имитации возвращаемых значений, чем параметров). В принципе, я не могу думать о том, что они делают проще ...
Возвращаемые значения FTW.
РЕДАКТИРОВАТЬ: с точки зрения того, что происходит ...
Обычно, когда вы передаете аргумент для параметра out, у вас есть для передачи переменной. (Элементы массива также классифицируются как переменные.) В вызываемом вами методе нет «новой» переменной в стеке для параметра - он использует вашу переменную для хранения. Любые изменения в переменной сразу видны. Вот пример, показывающий разницу:
using System;
class Test
{
static int value;
static void ShowValue(string description)
{
Console.WriteLine(description + value);
}
static void Main()
{
Console.WriteLine("Return value test...");
value = 5;
value = ReturnValue();
ShowValue("Value after ReturnValue(): ");
value = 5;
Console.WriteLine("Out parameter test...");
OutParameter(out value);
ShowValue("Value after OutParameter(): ");
}
static int ReturnValue()
{
ShowValue("ReturnValue (pre): ");
int tmp = 10;
ShowValue("ReturnValue (post): ");
return tmp;
}
static void OutParameter(out int tmp)
{
ShowValue("OutParameter (pre): ");
tmp = 10;
ShowValue("OutParameter (post): ");
}
}
Результаты:
Return value test...
ReturnValue (pre): 5
ReturnValue (post): 5
Value after ReturnValue(): 10
Out parameter test...
OutParameter (pre): 5
OutParameter (post): 10
Value after OutParameter(): 10
Разница заключается в шаге post, то есть после изменения локальной переменной или параметра. В тесте ReturnValue это не имеет значения для статической переменной value
. В тесте OutParameter переменная value
изменяется на строку tmp = 10;