C# ref в сравнении с out
Ключевые слова Ref
и out
в C# используются для передачи аргументов внутри метода или функции. Оба слова указывают на то, что аргумент/параметр передается по ссылке. По умолчанию параметры передаются в метод по значению. Используя эти ключевые слова (ref
и out
), мы можем передать параметр по ссылке.
Ключевое слово ref
Ключевое слово ref
передает аргументы по ссылке. Это означает, что любые изменения, внесенные в этот аргумент в методе, будут отражены в этой переменной, когда управление вернется к вызывающему методу.
Пример кода
public static string GetNextName(ref int id)
{
string returnText = "Next-" + id.ToString();
id += 1;
return returnText;
}
static void Main(string[] args)
{
int i = 1;
Console.WriteLine("Previous value of integer i:" + i.ToString());
string test = GetNextName(ref i);
Console.WriteLine("Current value of integer i:" + i.ToString());
}
Вывод
Ключевое слово out
Ключевое слово out
передает аргументы по ссылке. Это очень похоже на ключевое слово ref
.
Пример кода
public static string GetNextNameByOut(out int id)
{
id = 1;
string returnText = "Next-" + id.ToString();
return returnText;
}
static void Main(string[] args)
{
int i = 0;
Console.WriteLine("Previous value of integer i:" + i.ToString());
string test = GetNextNameByOut(out i);
Console.WriteLine("Current value of integer i:" + i.ToString());
}
Вывод
Ref в сравнении с Out
Ref |
Out |
Параметр или аргумент должен быть сначала инициализирован, прежде чем он будет передан в |
Инициализация параметра или аргумента перед передачей его в |
Не требуется присваивать или инициализировать значение параметра (который передается по |
Вызываемый метод обязан присвоить или инициализировать значение параметра (который передается в |
Передача значения параметра по |
Объявление параметра в методе |
Инициализация значения параметра перед его использованием в вызывающем методе не обязательна. |
Значение параметра должно быть инициализировано в вызывающем методе перед его использованием. |
Когда мы используем |
Когда мы используем |
И | |
Свойства не являются переменными, поэтому они не могут быть переданы в качестве параметра |
Ключевое слово Ref / Out и перегрузка методов
И ref
, и out
обрабатываются по-разному во время выполнения программы, и одинаково во время компиляции, поэтому методы не могут быть перегружены, если один метод принимает аргумент как ref
, а другой — как out
.
Пример кода
public static string GetNextName(ref int id)
{
string returnText = "Next-" + id.ToString();
id += 1;
return returnText;
}
public static string GetNextName(out int id)
{
id = 1;
string returnText = "Next-" + id.ToString();
return returnText;
}
Вывод при компиляции кода:
Однако перегрузка методов возможна, когда один метод принимает аргумент ref
или out
, а другой принимает тот же аргумент без ref
или out
.
Пример кода
public static string GetNextName(int id)
{
string returnText = "Next-" + id.ToString();
id += 1;
return returnText;
}
public static string GetNextName(ref int id)
{
string returnText = "Next-" + id.ToString();
id += 1;
return returnText;
}
Резюме
Ключевые слова out
и ref
полезны, когда мы хотим вернуть значение в тех же переменных, которые были переданы в качестве аргумента.
Материал подготовлен в рамках специализации «C# Developer». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.
Комментарии (12)
shai_hulud
27.09.2021 21:00+4Вся прелесть ref в C# раскрывается в работе с unmanaged code:
public unsafe struct uv_timer_t { // для ref можно делать extenstion методы public static void Stop(this ref uv_timer_t timerHandleRef) { var handlePtr = (IntPtr)Unsafe.AsPointer(ref handle); } [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] private static extern int uv_timer_stop(IntPtr handle); }
И далее в коде получаете поинтер на uv_timer_t в unmanaged памяти, преобразуете его в ref uv_timer_t и работаете уже почти как с настоящим типизированным объектом, вызываете методы, передаете дальше по стеку итд. Хранить нельзя, можно преобразовать обратно в IntPtr и хранить его.ref var timerRef = ref Unsafe.AsRef<uv_timer_t>((void*)POINTER_TO_UNMANAGED_MEMORY); timerRef.Stop(); // extension method на ref переменных работают by ref myFunc(ref timerRef); // можно передавать в методы, разыменовывать можно, но не нужно :)
DistortNeo
28.09.2021 00:20+1Хранить нельзя
А чтобы не было соблазна так делать, объявите типа как
ref struct
.
Mikluho
28.09.2021 00:41+3Чую, выпускники вашего курса будут заваливать интервью даже на позицию junior...
Это ж надо, так запутать простые объяснения...
По умолчанию параметры передаются в метод по значению.
Это справедливо для value-типов
Ключевое слово
out
передает аргументы по ссылке. Это очень похоже на ключевое словоref
.Это как так-то? А в чём разница? (да, там потом есть табличка, но вот прямо тут лажа).
Требования про инициализацию параметров раскрыта неверно. И про двунаправленную передачу тоже фигня написана...
Тема про ref и out для reference типов не раскрыта.
ad1Dima
28.09.2021 02:25-3Чую, выпускники вашего курса будут заваливать интервью даже на позицию junior...
Или нет
Politura
28.09.2021 04:03+5И что? Индусы пишущие статьи, за редким исключением балбесы набивающие себе стенд чисто для того, чтоб тыкая в свой профиль наняться на позицию пожирнее, и плюсуют их там исключительно такие-же индусы. Уровень их статей как правило ниже плинтуса, о чем говорит и эта статья.
Хочется плюсиков за переводы - переводите статьи нормальных чуваков, а не хрен пойми кого, например по C# вот: https://blog.marcgravell.com/
ad1Dima
28.09.2021 08:01-1будут заваливать интервью даже на позицию junior...
чтоб тыкая в свой профиль наняться на позицию пожирнее
Собственно о том и речь, пройдут и наймутся )
KGeist
28.09.2021 07:08+3>Это справедливо для value-типов
По умолчанию, ссылки на reference-объекты передаются по значению. Явно это имелось в виду. Можно передавать значение ссылки по ссылке, если использовать ref или out.
Mikluho
28.09.2021 08:20Оно как бы да, так и есть, но не многие понимают, что это значит и как работает.
А потом удивляются, что написанное в методе 'someStringVar = "42"; ' не работает.
DistortNeo
28.09.2021 14:01+1А можно ещё больше всех запутать и вспомнить про
in
.
Так-то иin
, иref
, иout
— это абсолютно одно и то же, но с разными ограничениями, накладываемым при компиляции.
moroz69off
01.10.2021 07:39Кроме информационной каши в тексте статьи есть ещё неприятность -- оформление. В таблице ключевое слово языка ref переживает три начертания: ref, Ref, REF. Куда это годится?
DistortNeo
И во время выполнения программы они тоже обрабатываются одинаково. Кстати, есть забавный хак: с помощью
System.Runtime.CompilerServices.Unsafe.SkipInit<T>
можно обойти требование об обязательной инициализацииout
-параметра в вызываемом методе.IvanG
Автор перепутал, во время компиляции они по разному обрабатываются, в out проверка на присвоение в методе есть, в ref - нет