Разница между параметрами ref и out в .NET

В чем разница между параметрами ref и out в .NET? В каких ситуациях один может быть полезнее другого? Каким будет фрагмент кода, в котором один можно использовать, а другой - нет?

На мой взгляд, это не дубликат упомянутого вопроса, потому что 1. он предшествовал этому вопросу 2. в этом вопросе есть детали, не относящиеся к «дубликату».

Dov Miller 04.12.2019 12:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
407
1
267 081
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

ref, вероятно, задохнется на null, поскольку он предположительно ожидает изменения существующего объекта. out ожидает null, поскольку возвращает новый объект.

Foo (ref null) не компилируется, но строка bar = null; Foo (ref bar); Это хорошо.

James Curran 26.09.2008 01:03

Подавиться нулевой константой? Как Джеймс Карран, вы не можете передавать константу в аргументе ref.

Andrei Rînea 26.09.2008 01:55

Я не имел в виду нулевую константу: я имел в виду переменную с нулевым значением.

Joel Coehoorn 28.09.2008 18:23

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

Параметры out инициализируются вызываемым методом, параметры ref инициализируются перед вызовом метода. Следовательно, параметры out используются, когда вам просто нужно получить вторичное возвращаемое значение, параметры ref используются для получения значения и, потенциально возвращающего изменение этого значения (во вторую очередь основного возвращаемого значения).

Ответ принят как подходящий

Они почти одинаковы - с той лишь разницей, что переменную, которую вы передаете как параметр out, не нужно инициализировать, но, передав ее как параметр ref, она должна иметь какое-то значение.

int x;
Foo(out x); // OK

int y;
Foo(ref y); // Error: y should be initialized before calling the method

Параметры Ref предназначены для данных, которые могут быть изменены, параметры out предназначены для данных, которые являются дополнительным выходом для функции (например, int.TryParse), которые уже используют возвращаемое значение для чего-то.

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

Jesse C. Slicer 05.02.2010 23:18

@Mike Ваше исправление НЕПРАВИЛЬНО. Это было правильно, «и метод, использующий параметр из, должен что-то установить». Метод, получающий параметр out, должен его инициализировать. Метод, получающий параметр ref, может делать с ним все, что хочет. Конечно, он может это игнорировать. Откатываю обратно.

xanatos 11.10.2011 15:06

Несомненно, главное отличие состоит в том, что ссылки находятся внутри и снаружи, тогда как out можно использовать только для возврата данных. рассматривать недействительные работы (ref int z) {Debug.WriteLine (z); } и void notWorks (out int z) {Debug.WriteLine (z); } или я упустил какой-то трюк, чтобы получить значение параметра out до его инициализации? Я заметил, что отладчик, например, может это сделать.

user159335 20.10.2011 14:51

Поэтому для параметров, которые должны быть установлены на что-то по пути, следует использовать ref. В противном случае используйте вне.

FistOfFury 24.09.2012 18:07

С другой стороны, ref может спасти дополнительную копию Struct от создания во время вызова функции. С другой стороны, класс может быть инициализирован нулевым значением, поэтому вам ВСЕ ЕЩЕ нужно остерегаться этого.

Michael Brown 05.10.2012 20:54

И еще одно отличие: x (параметр out) ДОЛЖЕН быть присвоено значение в функции foo, а ref МОЖНО присвоить значение в foo.

Stefan Steiger 30.04.2013 12:44

Этот ответ приуменьшает значение --- и без того тонкого --- различия между ними; это не лучший подход для обучения других.

jpaugh 01.05.2017 18:46

Почему в C# есть как ref, так и out?

Вызывающий метод, который принимает выходной параметр, не обязан назначать переменную, переданную как выходной параметр перед вызовом; однако перед возвратом вызываемый должен назначить параметр out.

Напротив, параметры ref считаются изначально назначенными вызывающей стороной. Таким образом, вызываемому не требуется назначать параметр ref перед использованием. Параметры ссылки передаются как в метод, так и из него.

Итак, out означает выход, а ref - вход и выход.

Они близко соответствуют параметрам [out] и [in,out] COM-интерфейсов, причем преимущества параметров out заключаются в том, что вызывающим абонентам не нужно передавать предварительно выделенный объект в тех случаях, когда он не нужен вызываемому методу - это позволяет избежать затрат на выделение и выделение ресурсов. и любые затраты, которые могут быть связаны с маршалингом (более вероятно, с COM, но не редко в .NET).

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

fpsColton 28.11.2014 20:49

В ссылке есть очень четкое объяснение разницы, лучше, чем большинство ответов здесь. Спасибо!

Hannish 12.01.2017 15:36

Ключевое слово ref используется для передачи значений по ссылке. (Это не препятствует тому, чтобы передаваемые значения были типами значений или ссылочными типами). Параметры вывода, указанные с ключевым словом out, предназначены для возврата значений из метода.

Одним из ключевых отличий кода является то, что вы должны установить значение выходного параметра внутри метода. Это не относится к параметрам ref.

Подробнее см. http://www.blackwasp.co.uk/CSharpMethodParameters.aspx

В этом Параметр out and ref в C# есть несколько хороших примеров.

Основное отличие заключается в том, что параметры out не нуждаются в инициализации при передаче, в то время как параметры ref это нужно.

out и ref точно такие же, за исключением того, что переменные out не нужно инициализировать перед отправкой в ​​бездну. Я не такой уж умен, я это скопировал из библиотеки MSDN :).

Однако, чтобы быть более ясным об их использовании, значение модификатора состоит в том, что если вы измените ссылку на эту переменную в своем коде, out и ref заставят вашу вызывающую переменную также изменить ссылку. В приведенном ниже коде переменная ceo будет ссылкой на newGuy, как только он вернется из вызова doStuff. Если бы не ref (или out), ссылка не была бы изменена.

private void newEmployee()
{
    Person ceo = Person.FindCEO();
    doStuff(ref ceo);
}

private void doStuff(ref Person employee)
{
    Person newGuy = new Person();
    employee = newGuy;
}

ref и out позволяют вызываемому методу изменять параметр. Разница между ними в том, что происходит до вы делаете звонок.

  • ref означает, что параметр имеет значение до, входящее в функцию. Вызываемая функция может читать и / или изменять значение в любое время. Параметр входит, затем выходит

  • out означает, что параметр не имеет официального значения до входа в функцию. Вызываемая функция должна его инициализировать. Параметр только гаснет

Вот мой любимый способ взглянуть на это: ref - передавать переменные по ссылке. out должен объявить вторичный возвращаемое значение для функции. Это как если бы вы могли написать это:

// This is not C#
public (bool, string) GetWebThing(string name, ref Buffer paramBuffer);

// This is C#
public bool GetWebThing(string name, ref Buffer paramBuffer, out string actualUrl);

Вот более подробный список эффектов каждой альтернативы:

Перед вызовом метода:

ref: вызывающий должен установить значение параметра перед передачей его вызываемому методу.

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

Во время разговора:

ref: вызываемый метод может прочитать аргумент в любое время.

out: вызываемый метод должен инициализировать параметр перед его чтением.

Удаленные звонки:

ref: текущее значение упорядочивается удаленному вызову. Дополнительная стоимость производительности.

out: удаленному вызову ничего не передается. Быстрее.

Технически говоря, вы всегда можете использовать ref вместо out, но out позволяет вам уточнить смысл аргумента, а иногда это может быть намного эффективнее.

Строка, упомянутая как «Это не C#», теперь на самом деле C#, начиная с C# 7 docs.microsoft.com/en-us/dotnet/csharp/whats-new/…

TJ Rockefeller 24.04.2020 19:42

Пример для OUT: переменная получает значение, инициализированное после входа в метод. Позже это же значение возвращается основному методу.

namespace outreftry
{
    class outref
    {
        static void Main(string[] args)
        {
            yyy a = new yyy(); ;

            // u can try giving int i=100 but is useless as that value is not passed into
            // the method. Only variable goes into the method and gets changed its
            // value and comes out. 
            int i; 

            a.abc(out i);

            System.Console.WriteLine(i);
        }
    }
    class yyy
    {

        public void abc(out int i)
        {

            i = 10;

        }

    }
}

Output:

10

===============================================

Пример для ссылки: переменная должна быть инициализирована перед переходом к методу. Позже то же значение или измененное значение будет возвращено основному методу.

namespace outreftry
{
    class outref
    {
        static void Main(string[] args)
        {
            yyy a = new yyy(); ;

            int i = 0;

            a.abc(ref i);

            System.Console.WriteLine(i);
        }
    }
    class yyy
    {

        public void abc(ref int i)
        {
            System.Console.WriteLine(i);
            i = 10;

        }

    }
}

Output:

    0
    10

=================================

Надеюсь, теперь все ясно.

  • Перед передачей переменную ref необходимо инициализировать.
  • Переменная out должна быть установлена ​​в вашей реализации функции.
  • Параметры out можно рассматривать как дополнительные возвращаемые переменные (не входные)
  • Параметры ref можно рассматривать как входные и выходные переменные.

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

ref указывает, что значение является ссылкой, имеющей значение, значение которой вы можете изменить внутри метода.

Параметры Ref и Out:

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

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


Ref Parameter : It has to be initialized before passing to the Method. The ref keyword on a method parameter causes a method to refer to the same variable that was passed as an input parameter for the same method. If you do any changes to the variable, they will be reflected in the variable.

int sampleData = 0; 
sampleMethod(ref sampleData);

Ex of Ref Параметр

public static void Main() 
{ 
 int i = 3; // Variable need to be initialized 
 sampleMethod(ref i );  
}

public static void sampleMethod(ref int sampleData) 
{ 
 sampleData++; 
} 

Out Parameter : It is not necessary to be initialized before passing to Method. The out parameter can be used to return the values in the same variable passed as a parameter of the method. Any changes made to the parameter will be reflected in the variable.

 int sampleData; 
 sampleMethod(out sampleData);

Ex из выходного параметра

public static void Main() 
{ 
 int i, j; // Variable need not be initialized 
 sampleMethod(out i, out j); 
} 
public static int sampleMethod(out int sampleData1, out int sampleData2) 
{ 
 sampleData1 = 10; 
 sampleData2 = 20; 
 return 0; 
} 

Параметр out - это параметр ref с добавленным специальным атрибутом Out(). Если параметр метода C# объявлен как out, компилятор потребует, чтобы параметр был записан, прежде чем его можно будет прочитать и до того, как метод сможет вернуться. Если C# вызывает метод, параметр которого включает атрибут Out(), компилятор, чтобы решить, сообщать ли об ошибках «неопределенной переменной», будет делать вид, что переменная записана непосредственно перед вызовом метода. Обратите внимание, что, поскольку другие языки .net не придают такое же значение атрибуту Out(), возможно, что вызов подпрограммы с параметром out не повлияет на рассматриваемую переменную. Если переменная используется в качестве параметра out до того, как она будет определенно назначена, компилятор C# сгенерирует код, чтобы гарантировать, что она будет очищена в какой-то момент перед ее использованием, но если такая переменная покидает и повторно входит в область видимости, нет никаких гарантий что он снова будет очищен.

из:

В C# метод может возвращать только одно значение. Если вы хотите вернуть более одного значения, вы можете использовать ключевое слово out. Модификатор out возвращается как возврат по ссылке. Самый простой ответ - ключевое слово «out» используется для получения значения из метода.

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

ссылка:

В C#, когда вы передаете тип значения, такой как int, float, double и т. д., В качестве аргумента параметра метода, он передается по значению. Следовательно, если вы измените значение параметра, это не повлияет на аргумент в вызове метода. Но если вы отметите параметр ключевым словом «ref», он отразится в фактической переменной.

  • Перед вызовом функции вам необходимо инициализировать переменную.
  • Присваивать какое-либо значение параметру ref в методе не обязательно. Если вы не меняете значение, зачем помечать его как «ref»?

Они немного разные.

Параметр out не нужно инициализировать вызываемым пользователем перед передачей в метод. Следовательно, любой метод с параметром out

  • Невозможно прочитать параметр до присвоения ему значения
  • Необходимо присвоить ему значение перед возвратом

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


Параметр ref должен быть инициализирован вызываемым пользователем перед передачей его методу. Следовательно, любой метод с параметром ref

  • Можно проверить значение перед его присвоением
  • Может вернуть исходное значение, нетронутое

Это используется для метода, который должен (например) проверить свое значение и проверить его или нормализовать.

out получил новый более лаконичный синтаксис в C# 7 https://docs.microsoft.com/en-us/dotnet/articles/csharp/whats-new/csharp-7#more-expression-bodied-members и еще более захватывающим является усовершенствование кортежей C# 7, которое является более элегантным выбором, чем использование ref и out IMHO.

Другие вопросы по теме