Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1447 / 157 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Лекция 8:

Основы языка C#. Часть 2

< Лекция 7 || Лекция 8: 12 || Лекция 9 >

Ссылочные параметры, определенные явно

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

Добавим в предыдущем примере в объявление и вызов первых двух параметров метода Add() модификатор ref ( reference - ссылка), заставляющий компилятор включить механизм передачи этих параметров по ссылке. Код станет таким

using System;
    
static class Calculator
{
    public static int Add(ref int x, ref int y, out int a, out int b)
    {
        int answer = x + y;
        x = 10; y = 20; a = 30; b = 40;
        return answer;
    }
}
    
class Start
{
    static void Main()// Вызывающая сторона
    {
        // Настройка консоли
        Console.Title = "Передача параметров по ссылке";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
    
        int x = 1, y = 2, a = 3, b = 4;
        Console.WriteLine("До вызова: \tx={0}; 
          y={1}; a={2}; b={3}",
            x, y, a, b);
        Calculator.Add(ref x, ref y, out a, out b);
        Console.WriteLine("После вызова: \tx={0}; 
          y={1}; a={2}; b={3}",
            x, y, a, b);
    
        Console.ReadLine();
    }
}
Листинг 8.3 . Передача параметров по ссылке

Получим результат


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

Ссылочные параметры, определенные неявно

Объекты ссылочного типа адресуются в программе ссылками. Их также можно передать методам по значению. Только при этом в методе создается не копия объекта, а копия ссылки ( alias - псевдоним), которая будет адресоваться к тому же объекту. Это значит, что метод будет работать с самим переданным объектом, а не с его копией. Но попытка изменить значение самого псевдонима никак не отразится на переданной из клиента ссылке - она в клиенте по-прежнему будет адресоваться к самому объекту.

using System;
    
class MyClass
{
    // Открытые поля
    public int a, b;
    
    // Конструктор
    public MyClass(int a, int b)
    {
        this.a = a;
        this.b = b;
    }
    
    // Печать
    public void Show()
    {
        Console.WriteLine("a={0}, b={1}", a, b);
    }
}
    
class Start
{
    static void ChangeObject(MyClass ob)
    {
        ob.a = 10;
        ob.b = 20;
    
        ob = null; // Изменяем копию ссылки
    }
    
    static void Main()// Вызывающая сторона
    {
        // Настройка консоли
        Console.Title = "Передача методу объекта ссылочного типа";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
    
        // Создаем объект
        MyClass ob1 = new MyClass(1, 2);
    
        Console.Write("До вызова: \t"); ob1.Show();
    
        // Передаем методу объект в виде ссылки 
        ChangeObject(ob1);
    
        Console.Write("После вызова: \t"); ob1.Show();
    
        Console.ReadLine();
    }
}
Листинг 8.4 . Передача методу объекта ссылочного типа

Результат будет таким


Если в метод передать ссылку на объект с модификатором ref, тогда в методе окажется адресная переменная самой ссылки (ссылка на ссылку) и смена значения этой адресной переменной изменит значение ссылки, что приведет к потере объекта или к адресации на новый объект.

using System;
    
static class Swap
{
    public static void SwapRef(ref string str1, ref string str2)
    {
        string tmp = str1;
        str1 = str2;
        str2 = tmp;
    }
}
    
class Start
{
    static void Main()// Вызывающая сторона
    {
        // Настройки консоли
        Console.Title = "Обмен строк через адреса";
        Console.ForegroundColor = ConsoleColor.White; // Белый текст
        Console.WindowWidth = 45;// Знакомест клиентской области
        Console.WindowHeight = 3;// Строк клиентской области
        Console.CursorVisible = false;
    
        // Вызывающий код
        string string1 = "Первая строка";
        string string2 = "Вторая строка";
        Console.WriteLine("До вызова: \t{0}, 
          {1}", string1, string2);
        Swap.SwapRef(ref string1, ref string2);
        Console.WriteLine("После вызова: \t{0}, 
          {1}", string1, string2);
    
        Console.ReadLine();
    }
}
Листинг 8.5 . Метод обменивает значения ссылок на строки клиента

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

Результат выполнения будет таким


Вот еще один пример.

using System;
using System.IO;
using System.Text;
    
class MyClass
{
    // Печать в свойство, базового поля нет
    public String Result
    {
        get
        {
            return String.Format("a={0}, b={1}", a, b);
        }
    }
    
    // Закрытые поля
    int a, b;
    
    // Конструктор
    public MyClass(int a, int b)
    {
        this.a = a;
        this.b = b;
    }
    
    public static void SwapRef(ref MyClass ob1, 
      ref MyClass ob2, ref MyClass obNew)
    {
        MyClass tmp;// Объявляем вспомогательную ссылку
    
        // Обмениваем значения ссылок
        tmp = ob1;
        ob1 = ob2;
        ob2 = tmp;
    
        // Создаем новый объект и прикрепляем к ссылке клиента
        obNew = new MyClass(5, 6);
    }
}
    
class Start
{
    static void Main()// Вызывающая сторона
    {
        // Настройки консоли
        Console.Title = "Обмен объектов через адреса";
        Console.ForegroundColor = ConsoleColor.White; // Белый текст
        Console.CursorVisible = false;
    
        // Создаем и открываем поток вывода в файл
        StreamWriter writeFile =
            new StreamWriter(@"C:\1\xx.txt", false, 
            ASCIIEncoding.GetEncoding(1251));
    
        // Вызывающий код
        // Создаем объекты
        MyClass ob1 = new MyClass(1, 2);
        MyClass ob2 = new MyClass(3, 4);
    
        // Создаем ссылку без объекта
        MyClass ob3 = null;
    
        writeFile.WriteLine("До вызова: ");
        writeFile.WriteLine(ob1.Result);
        writeFile.WriteLine(ob2.Result);
        writeFile.WriteLine();
    
        // Передаем методу объект в виде ссылки 
        MyClass.SwapRef(ref ob1, ref ob2, ref ob3);
    
        writeFile.WriteLine("После вызова: ");
        writeFile.WriteLine(ob1.Result);
        writeFile.WriteLine(ob2.Result);
        writeFile.WriteLine(ob3.Result);
    
        writeFile.Close();
    }
}
Листинг 8.6 . Метод обменивает значения ссылок на объекты клиента

Результат выполнения будет размещен в автоматически созданном текстовом файле с нашим именем xx.txt и будет таким

До вызова: 
a=1, b=2
a=3, b=4

После вызова: 
a=3, b=4
a=1, b=2
a=5, b=6

В последнем приведенном коде мы немножко отвлеклись от темы и сделали вывод результатов в текстовый файл, чтобы не приводить снимки экрана, которые занимают больше места в данном описании, чем текст. Для этого потребовались дополнительные пространства имен: System.IO и System.Text. Для простоты мы выборку значений внутренних полей класса выполнили через строковое свойство, а для вывода в поток воспользовались методом WriteLine() класса System.IO.StreamWriter. В дальнейшем иногда мы будем придерживаться именно такого подхода, чтобы иметь возможность копировать результаты в текстовом виде.

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

Project/Имя_проекта Properties/Application/Output type/Windows Application

Здесь мы отключаем появление консольного окна, но не создаем графическое окно Windows, которое нам не нужно, поскольку вывод выполняется в файл.

Передача методу переменного количества аргументов

Иногда необходимо, чтобы метод принимал произвольное число аргументов. Для этого при объявлении метода применяется специальный параметр, который заменяет собой произвольное количество однотипных параметров. Этот параметр объявляется как массив с ключевым словом params. Он организует прием произвольного количества аргументов, в том числе и нулевое. Важно, чтобы множественный параметр при объявлении стоял последним в списке параметров метода.

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

using System;
using System.IO;
using System.Text;
    
class Min
{
    // Печать в статическое свойство
    static String result;
    public static String Result
    {
        get
        {
            return result;
        }
    }
     
    public static void MinValue(params int[] nums)
    {
        if (nums.Length == 0)
        {
            result = "Нет аргументов";
            return;
        }
    
        int min = nums[0];
        for (int i = 1; i < nums.Length; i++)
            if (nums[i] < min)
                min = nums[i];
    
        result = "Минимум равен " + min;
    }
}
    
class Start
{
    static void Main()// Вызывающая сторона
    {
        // Создаем и открываем поток вывода в файл
        StreamWriter writeFile =
            new StreamWriter(@"C:\1\xx.txt", false, ASCIIEncoding.
                    GetEncoding(1251));
    
        // Вызывающий код
        Min.MinValue(10, 20, 30, 40, 50);
        writeFile.WriteLine(Min.Result);
        Min.MinValue();
        writeFile.WriteLine(Min.Result);
    
        writeFile.Close();
    }
}
Листинг 8.7 . Использование множественного параметра

Результат выполнения

Минимум равен 10
Нет аргументов
< Лекция 7 || Лекция 8: 12 || Лекция 9 >
Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

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

 

Как активировать код?