Параметры методов. Модификаторы ref и out. Примеры. Отличия между модификаторами ref и out
Содержание
- 1. Применение модификатора параметра ref. Какое назначение модификатора параметра ref?
- 2. Примеры методов, которые используют модификатор параметра ref
- 3. Применение модификатора параметра out. Какое назначение модификатора параметра out?
- 4. Примеры методов, которые используют модификатор параметра out
- 5. Какие существуют отличия между модификаторами ref и out?
- 6. Передача в функцию ссылки на экземпляр класса с использованием модификатора ref. Пример
- 7. Передача в функцию ссылки на экземпляр класса с использованием модификатора out. Пример
- Связанные темы
Поиск на других ресурсах:
1. Применение модификатора параметра ref. Какое назначение модификатора параметра ref?
Модификатор ref предназначен для указания того, что параметр метода должен передаваться по ссылке а не по значению. Другими словами, если у методу нужно принудительно передать аргумент по ссылке, то при объявлении метода перед соответствующим формальным параметром нужно указать модификатор ref.
Модификатор параметра ref используется в описании формального параметра метода. Модификатор параметра ref указывается перед типом формального параметра, как показано ниже:
ref type param
Общая форма метода в классе, который получает формальный параметр ref следующая:
access return_type MethodName(ref type param) { // ... }
где
- MethodName – имя метода;
- access – тип доступа к методу (private, protected, public, internal);
- return_type – тип, возвращаемый методом;
- type – тип параметра с именем param, который получает метод;
- param – имя формального параметра.
При вызове такого метода из другого кода, перед параметром также ставится модификатор ref:
MethodName(ref argument);
где argument – аргумент, который передается в метод. Этого требует синтаксис C#.
⇑
2. Примеры методов, которые используют модификатор параметра ref
Пример 1. Реализация метода, который умножает число на 5. Число есть входным параметром метода. Метод получает значение числа, умножает его на 5 и возвращает с помощью модификатора ref. То есть, метод увеличивает в 5 раз значение аргумента.
// метод, который увеличивает параметр x в 5 раз public void Mult5(ref int x) { x = x * 5; }
Вызов метода Mult5() из другого программного кода
int d = 10; qe.Mult5(ref d); // d = 10*5 = 50
После вызова, значение переменной d становится равным 50. Согласно синтаксису C#, перед вызовом переменной d нужно ставить модификатор параметра ref.
Пример 2. Решение квадратного уравнения. Задан класс QuadraticEquation, содержащий данные и метод решения квадратного уравнения.
В классе реализован метод Calc(), получающий два параметра x1, x2 с модификатором ref. Эти параметры изменяют свои значения в методе, в случае, если уравнение имеет решение.
// класс, который реализует данные и метод решения квадратного уравнения class QuadraticEquation { public double a, b, c; // конструктор класса, получает параметрами коэффициенты a, b, c уравнения public QuadraticEquation(double _a, double _b, double _c) { if (IsSolution(a, b, c)) { a = _a; b = _b; c = _c; } else a = b = c = 0; } // внутренний метод, который определяет, имеет ли решение уравнение с задаными a,b,c bool IsSolution(double a, double b, double c) { double d = b * b - 4 * a * c; if (d < 0) return false; return true; } // Метод, который решает квадратное уравнение // Метод возвращает true и результат в x1, x2, если уравнение имеет решение, // в противном случае метод возвращает false public bool Calc(ref double x1, ref double x2) { // проверка, имеет ли уравнение решение if (!IsSolution(a, b, c)) return false; // если решение есть, то вычисляются x1, x2 double d = b * b - 4 * a * c; x1 = (-b - Math.Sqrt(d)) / (2 * a); x2 = (-b + Math.Sqrt(d)) / (2 * a); return true; } }
Вызов метода из другого класса может быть таким как описан низшее
class Program { static void Main(string[] args) { // создание объекта класса QuadraticEquation QuadraticEquation qe = new QuadraticEquation(2, -8, 5); double x1 = 0, x2 = 0; if (qe.Calc(ref x1, ref x2)) // вызов метода Calc(), перед x1, x2 задается модификатор ref { // если есть решение, то вывести корни уравнения x1, x2 Console.WriteLine("x1 = {0}", x1); Console.WriteLine("x2 = {0}", x2); } else Console.WriteLine("Уравнение не имеет корней."); return; } }
Следует заметить, что при вызове метода Calc() обязательно указываются модификаторы ref:
Calc(ref x1, ref x2)
Пример 3. Дана строка s. Разработать метод, который удаляет из строки s заданный символ c. Символ c есть входным параметром-значением. Строка s должна быть параметром-ссылкой и результатом.
Ниже приводится класс Str с реализацией метода DeleteSymbol(). Также продемонстрирован вызов метода DeleteSymbol() из функции Main().
class Str { // метод удаляет из строки s символ c public void DeleteSymbol(ref string s, char c) { string s2=""; for (int i=0; i<s.Length; i++) if (s[i] != c) s2 = s2 + s[i]; s = s2; } } class Program { static void Main(string[] args) { Str S = new Str(); string str = "This is a textbook."; // вызов метода DeleteSymbol S.DeleteSymbol(ref str, 'i'); // str = "Ths s a textbook." Console.WriteLine(str); return; } }
⇑
3. Применение модификатора параметра out. Какое назначение модификатора параметра out?
Модификатор параметра out используется, если необходимо выполнение двух условий:
- методу не нужно передавать значение;
- метод обязательно должен возвращать значение с помощью параметра.
Модификатор out для параметра с именем param типа type указывается в начале его объявления
out type param
Общая форма метода, который получает один параметр с модификатором out имеет вид
access return_type MethodName(out type param) { // ... }
где
- MethodName – имя метода;
- access – тип доступа к методу (private, protected, public, internal);
- return_type – тип, который возвращает метод;
- type – тип параметра с именем param, который получает метод;
- param – имя формального параметра.
⇑
4. Примеры методов, которые используют модификатор параметра out
Пример 1. Разработать метод, который возвращает число Авогадро. Число Авогадро задается параметром метода.
Текст метода:
// число Авогадро void GetAvogadro(out double Avg) { Avg = 6.022140857e23; }
Вызов метода из другого программного кода
// вызов метода GetAvogadro() из другого метода double Avg; GetAvogadro(out Avg); // указание модификатора out - обязательно // Avg = 6.022140857E+23
Как видно из вышеприведенного кода, при вызове метода, который содержит out-параметр, обязательно нужно указывать модификатор out
GetAvogadro(out Avg);
Пример 2. Разработать метод CalcEquation(), который решает квадратное уравнение. Метод получает входными параметрами коэффициенты уравнения a, b, c. Эти параметры передаются в уравнение по значению.
Метод возвращает решение уравнения с помощью параметров x1, x2, которые объявлены с модификатором out.
Метод возвращает true с помощью оператора return, если уравнение имеет решение. В противном случае, метод возвращает false.
Ниже приведен класс Program, в котором реализован метод CalcEquation().
class Program { static bool CalcEquation(double a, double b, double c, out double x1, out double x2) { double d; d = b * b - 4 * a * c; if (d>=0) { x1 = (-b - Math.Sqrt(d)) / (2 * a); x2 = (-b + Math.Sqrt(d)) / (2 * a); return true; } else { x1 = x2 = 0; // обязательно, иначе ошибка return false; } } static void Main(string[] args) { // Демонстрация использования модификатора параметра out bool res; double x1, x2; // вызов метода res = CalcEquation(8, 3, -4, out x1, out x2); if (res) { Console.WriteLine("x1 = {0}", x1); Console.WriteLine("x2 = {0}", x2); } else Console.WriteLine("Уравнение не имеет корней"); return; } }
Пример 3. Разработать метод, который возвращает название цифры в строке.
// класс, который реализует метод, возвращающий название цифры class Number { // вывод названия числа на основе входного значения num public void TextNumber(int num, out string text) { switch (num) { case 1: text = "one"; break; case 2: text = "two"; break; case 3: text = "three"; break; case 4: text = "four"; break; case 5: text = "five"; break; case 6: text = "six"; break; case 7: text = "seven"; break; default: text = ""; break; } return; } }
Использование метода TextNumber() класса Number
Number nm = new Number(); // nm - объект класса Number string s; nm.TextNumber(3, out s); // s = "three" nm.TextNumber(8, out s); // s = "" nm.TextNumber(1, out s); // s = "one'
⇑
5. Какие существуют отличия между модификаторами ref и out?
Между модификаторами ref и out есть три взаимосвязанных отличия:
- 1. Параметр с модификатором out используется только для возвращения значения из метода. Параметр с модификатором ref может использоваться и для возвращения и для установки значения в методе другим переменным. Поэтому, перед вызовом метода, нет потребности присваивать какое-то значение переменной, которая используется с модификатором out.
- 2. В методе, переменная объявленная с параметром out считается неинициализированной. Переменная, объявленная с ref считается инициализированной. Поэтому, нельзя использовать out-переменную в правой части оператора присваивания. А ref-переменную можно.
- 3. Если параметр объявлен с модификатором out, то в теле метода этому параметру обязательно должно быть присвоено какое-то значение. Иначе будет ошибка компиляции. Если параметр объявлен с модификатором ref, то этому параметру присваивать значения в теле метода не обязательно.
⇑
6. Передача в функцию ссылки на экземпляр класса с использованием модификатора ref. Пример
В функцию можно передавать не только значение базовых типов (int, double, char и т.д.) но и значение экземпляров класса (объектов). Если при передаче в функцию объекта класса используются модификаторы ref или out, то сама ссылка передается по ссылке. Это позволяет изменять сам объект в методе.
Пример. В примере реализован метод, который заменяет один объект класса на другой. Оба объекта класса передаются в метод как параметры. Объект, который нужно заменить, передается с модификатором ref.
using System; using static System.Console; namespace ConsoleApp2 { // Класс Point - описывает точку на координатной плоскости class Point { // внутренние поля класса int x; int y; // Конструктор public Point(int x, int y) { this.x = x; this.y = y; } // Метод присваивания одного экземпляра класса другому: // point1 <= point2 public void AssignmentPoint(ref Point point1, Point point2) { point1 = point2; // переопределение объекта point1 } // Метод, который выводит значения полей класса public void Print(string text) { Write(text); WriteLine("x = {0}, y = {1}", x, y); } } class Program { static void Main(string[] args) { // Передача ссылок на объекты как ref- и out-параметров // 1. Объявить экземпляры классов Point pt1 = new Point(1, 2); Point pt2 = new Point(5, 6); // 2. Вывести экземпляры классов pt1.Print("Object pt1:"); pt2.Print("Object pt2:"); // 3. Вызов метода AssignmentPoint() - передача объекта как ref-ссылки pt1.AssignmentPoint(ref pt1, pt2); // pt1 <= pt2 // 4. Вывести экземпляры классов после присваивания WriteLine("\nAfter AssignmentPoint"); pt1.Print("Object pt1:"); pt2.Print("Object pt2:"); } } }
Результат выполнения программы
Object pt1:x = 1, y = 2 Object pt2:x = 5, y = 6 After AssignmentPoint Object pt1:x = 5, y = 6 Object pt2:x = 5, y = 6
Проанализировав результат работы программы можно прийти к заключению. В методе AssignmentPoint() состоялась полная замена объекта pt1 на объект pt2. Это возможно благодаря модификатору ref. Если убрать модификатор ref с первого параметра метода AssignmentPoint(), тогда изменения внутри метода не будут действовать в вызывающем коде (функции main()). Чтобы проверить это, достаточно убрать модификатор ref в методе AssignmentPoint() и в вызове этого метода.
⇑
7. Передача в функцию ссылки на экземпляр класса с использованием модификатора out. Пример
Экземпляр класса может быть передан в функцию с модификатором out. При такой передаче можно изменять сам экземпляр класса как и в случае с ref-модификатором.
Пример. В примере реализован метод FormArray(), формирующий новый объект класса ArrayDouble, выделяя для него память и заполняя произвольным значением. В вызывающем коде (функции main()) метод получает экземпляр класса со значением null.
using System; using static System.Console; namespace ConsoleApp2 { // Класс, реализующий массив чисел class ArrayDouble { private double[] A; // массив чисел // Конструктор с 1 параметром public ArrayDouble(int length) { // выделить память для массива и заполнить его нулевыми значениями A = new double[length]; for (int i = 0; i < A.Length; i++) { A[i] = 0.0; } } // Методы доступа public double GetAi(int index) { if ((index >= 0) && (index < A.Length)) return A[index]; else return 0; } public void SetAi(int index, double value) { if ((index >= 0) && (index < A.Length)) A[index] = value; } // Метод, который выводит массив в строку public void Print(string text) { WriteLine(text); for (int i = 0; i < A.Length; i++) { Write("{0:f2}\t", A[i]); } WriteLine(); } } class Program { // Метод, который заполняет массив типа ArrayDouble случайными числами, // метод формирует полностью новый экземпляр класса ArrayDouble static void FormArray(out ArrayDouble A, int length) { // 1. Инициализировать генератор случайных чисел Random rnd_num = new Random(); // 2. Выделить память для экземпляра A A = new ArrayDouble(length); // 3. Заполнить экземпляр A случайными числами от 0 до 10 for (int i = 0; i < length; i++) { A.SetAi(i, rnd_num.NextDouble() * 10); } } static void Main(string[] args) { ArrayDouble ad = null; // экземпляр класса ArrayDouble // Сформировать массив ad // параметр out - массив формируется внутри метода FormArray() Program.FormArray(out ad, 5); ad.Print("1 - Array ad:"); // Повторно сформировать массив ad FormArray(out ad, 7); // на выходе из метода - новый экземпляр ad.Print("2 - Array ad:"); } } }
Результат выполнения программы
1 - Array ad: 4.67 8.74 2.64 4.83 0.34 2 - Array ad: 6.65 6.66 4.32 1.24 8.30 9.73 3.13
⇑
Связанные темы
- Понятие метода. Примеры методов в классах. Возврат из метода. Оператор return. Методы без параметров. Ключевое слово void
- Модификаторы параметров ref и out. Примеры. Отличия между модификаторами ref и out
- Переменное количество аргументов в методах. Модификатор params. Преимущества. Примеры методов с переменным количеством аргументов
- Передача массивов в методы. Примеры. Передача массивов структур, классов, перечислений. Передача двумерных массивов в методы. Возврат массива из метода
- Необязательные аргументы. Преимущества. Примеры применения необязательных аргументов. «Неоднозначность» в необязательных аргументах
- Именованные аргументы. Преимущества. Примеры