Что лучше, возвращаемое значение или параметр out?



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



public int GetValue(); 


или:



public void GetValue(out int x);


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



спасибо.

759   16  

16 ответов:

возвращаемые значения почти всегда правильный выбор, когда метод не имеет ничего, чтобы вернуться. (На самом деле, я не могу придумать ни одного случая, когда бы я когда-нибудь хотите метод void с out параметр, если бы у меня был выбор. C# 7's Deconstruct методы деконструкции с поддержкой языка действуют как очень, очень редкое исключение из этого правила.)

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

int foo;
GetValue(out foo);

vs

int foo = GetValue();

значения Out также предотвращают цепочку методов следующим образом:

Console.WriteLine(GetValue().ToString("g"));

(действительно, это одна из проблем с установщиками свойств, и именно поэтому шаблон builder использует методы, которые возвращают builder, например myStringBuilder.Append(xxx).Append(yyy).)

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

возвращаемые значения FTW.

EDIT: с точки зрения того, что происходит...

в основном, когда вы передаете аргумент для параметра "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;

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

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

int foo = GetValue();

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

int foo;
GetValue(out foo);

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

обновление

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

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

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

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

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

    return input;
}

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

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

есть одна причина использовать out param, который еще не был упомянут: вызывающий метод обязан его получить. Если ваш метод создает значение, которое вызывающий не должен отбрасывать, делая его 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", но могут быть обстоятельства, когда это важно.

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

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

public class Result{
  public Person Person {get;set;}
  public int Sum {get;set;}
}

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

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

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

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

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

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

public int Value
{
    get;
    private set;
}

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

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

Если вы используете return, то данные сначала записываются в стек методов, а затем в вызывающий метод. в то время как в случае out, он непосредственно записывается в стек вызывающих методов. Не уверен, что есть еще какие-то различия.

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

однако есть некоторые незначительные различия , но не из них действительно важны:

использование параметра out заставит вас использовать две строки, такие как:

int n;
GetValue(n);

при использовании возвращаемого значения позволит вам сделать это в одну строку:

int n = GetValue();

другое отличие (корректно только для типов значений и только если C# не встроен функция) заключается в том, что использование возвращаемого значения обязательно сделает копию значения, когда функция возвращает при использовании параметра OUT не обязательно будет делать это.

как другие сказали: возвращаемое значение, а не из param.

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

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

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

кроме того, возвращаемые значения совместимы с асинхронными парадигмами проектирования.

вы не можете назначить функцию "async", если она использует параметры ref или out.

в целом, Возвращаемые Значения разрешить цепочку методов, более чистый синтаксис (устраняя необходимость для вызывающего объекта объявлять дополнительные переменные) и разрешить асинхронные конструкции без необходимости существенных изменений в будущем.

используя ключевое слово out с возвращаемым типом bool, иногда можно уменьшить раздувание кода и повысить читаемость. (В первую очередь, когда дополнительная информация в out param часто игнорируется.) Например:

var result = DoThing();
if (result.Success)
{
    result = DoOtherThing()
    if (result.Success)
    {
        result = DoFinalThing()
        if (result.Success)
        {
            success = true;
        }
    }
}

vs:

var result;
if (DoThing(out result))
{
    if (DoOtherThing(out result))
    {
        if (DoFinalThing(out result))
        {
            success = true;
        }
    }
}

out является более полезным, когда вы пытаетесь вернуть объект, который вы объявляете в методе.

пример

public BookList Find(string key)
{
   BookList book; //BookList is a model class
   _books.TryGetValue(key, out book) //_books is a concurrent dictionary
                                     //TryGetValue gets an item with matching key and returns it into book.
   return book;
}

возвращаемое значение это нормальное значение, которое возвращается методом.

где out parameter, well out и ref - это 2 ключевых слова C#, которые позволяют передавать переменные как ссылка.

большая разница между ref и out есть ref должны быть инициализированы до и out не

Comments

    Ничего не найдено.