Что лучше, возвращаемое значение или выходной параметр? - PullRequest
138 голосов
/ 01 мая 2009

Если мы хотим получить значение из метода, мы можем использовать любое возвращаемое значение, например:

public int GetValue(); 

или

public void GetValue(out int x);

Я не очень понимаю разницу между ними, и поэтому не знаю, что лучше. Ты можешь мне это объяснить?

Спасибо.

Ответы [ 17 ]

150 голосов
/ 01 мая 2009

Возвращаемые значения почти всегда правильный выбор, когда у метода больше нечего возвращать. (На самом деле, я не могу вспомнить ни одного случая, когда я бы когда-либо хотел бы метод 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;

26 голосов
/ 01 мая 2009

Что лучше, зависит от вашей конкретной ситуации. Одна из причин, по которым существует out, заключается в том, чтобы облегчить возврат нескольких значений из одного вызова метода:

public int ReturnMultiple(int input, out int output1, out int output2)
{
    output1 = input + 1;
    output2 = input + 2;

    return input;
}

Так что одно не по определению лучше другого. Но обычно вы хотите использовать простой возврат, если, например, у вас нет описанной выше ситуации.

EDIT: Это пример, демонстрирующий одну из причин существования ключевого слова. Вышесказанное ни в коем случае нельзя считать наилучшей практикой.

23 голосов
/ 01 мая 2009

Обычно вы предпочитаете возвращаемое значение, а не выходное значение. Наши параметры - это ненужное зло, если вы обнаружите, что пишете код, который должен сделать 2 вещи. Хорошим примером этого является шаблон Try (например, Int32.TryParse).

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

int foo = GetValue();

Обратите внимание, что я могу объявить переменную и назначить ее через ваш метод в одну строку. Для второго примера это выглядит так ...

int foo;
GetValue(out foo);

Теперь я вынужден объявить мою переменную заранее и написать код в две строки.

обновление

Хорошее место, где можно задать вопрос такого типа, - Руководство по проектированию .NET Framework. Если у вас есть книжная версия, вы можете увидеть аннотации Андерса Хейлсберга и других на эту тему (стр. 184-185), но онлайн-версия находится здесь ...

http://msdn.microsoft.com/en-us/library/ms182131(VS.80).aspx

Если вы обнаружите, что вам нужно вернуть две вещи из API, тогда лучше обернуть их в структуру / класс, чем выходной параметр.

12 голосов
/ 17 февраля 2014

Есть одна причина использовать параметр out, который еще не был упомянут: вызывающий метод обязан его получить. Если ваш метод выдает значение, которое вызывающая сторона не должна отбрасывать, сделав его out, вынуждает его специально принять его:

 Method1();  // Return values can be discard quite easily, even accidentally

 int  resultCode;
 Method2(out resultCode);  // Out params are a little harder to ignore

Конечно, вызывающий может все еще игнорировать значение в параметре out, но вы обратили на это свое внимание.

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

8 голосов
/ 01 мая 2009

Это предпочтение в основном

Я предпочитаю возвраты, и если у вас есть несколько возвратов, вы можете заключить их в результат DTO

public class Result{
  public Person Person {get;set;}
  public int Sum {get;set;}
}
5 голосов
/ 01 мая 2009

Вы должны почти всегда использовать возвращаемое значение. Параметры 'out' создают небольшие трения ко многим API, композиционности и т. Д.

Самое примечательное исключение, которое приходит на ум, - это когда вы хотите вернуть несколько значений (.Net Framework не имеет кортежей до 4.0), например, с шаблоном TryParse.

4 голосов
/ 01 мая 2009

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

В этих случаях необходимо учитывать только параметры.

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

2 голосов
/ 01 мая 2009

Я бы предпочел следующее вместо одного из этих в этом простом примере.

public int Value
{
    get;
    private set;
}

Но они все очень похожи. Обычно можно использовать «out», только если им нужно передать несколько значений обратно из метода. Если вы хотите отправить значение в метод и из него, выберите «ref». Мой метод лучше всего подходит, если вы только возвращаете значение, но если вы хотите передать параметр и вернуть значение, вы, вероятно, выберете ваш первый выбор.

1 голос
/ 01 мая 2009

Я думаю, что один из немногих сценариев, в которых это было бы полезно, был бы при работе с неуправляемой памятью, и вы хотите сделать очевидным, что «возвращаемое» значение следует удалять вручную, а не ожидать его удаления сам по себе.

1 голос
/ 01 мая 2009

Как говорили другие: возвращаемое значение, а не выходное значение.

Могу ли я порекомендовать вам книгу "Руководство по проектированию рамок" (2-е изд)? Страницы 184-185 раскрывают причины, по которым следует избегать использования параметров. Вся книга будет направлять вас в правильном направлении по всем видам проблем кодирования .NET.

В союзе с Framework Design Guidelines используется инструмент статического анализа FxCop. Вы найдете это на сайтах Microsoft для бесплатной загрузки. Запустите это на своем скомпилированном коде и посмотрите, что он говорит. Если он жалуется на сотни и сотни вещей ... не паникуйте! Посмотрите спокойно и внимательно на то, что говорится о каждом конкретном случае. Не спешите исправлять вещи как можно скорее. Учитесь на том, что это говорит вам. Вас отправят в путь к мастерству.

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