Параметры методов. Модификаторы ref и out. Примеры. Отличия между модификаторами ref и out

Параметры методов. Модификаторы ref и out. Примеры. Отличия между модификаторами ref и 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, то этому параметру присваивать значения в теле метода не обязательно.

 


Связанные темы