Выбрать главу

Примеры преобразований

Перейдем к примерам. Класс Testing, содержащий примеры, представляет собой набор данных разного типа, над которыми выполняются операции, иллюстрирующие преобразования типов. Вот описание класса Testing;

using System;

namespace Types

{

    /// <summary>

    /// Класс Testing включает данные разных типов. Каждый его

    /// открытый метод описывает некоторый пример,

    /// демонстрирующий работу с типами.

    /// Открытые методы могут вызывать закрытые методы класса.

    /// </summary>

    public class Testing

    {

         /// <summary>

         /// набор скалярных данных разного типа.

         /// </summary>

         byte b = 255;

         int x = 11;

         uint ux = 1111;

         float у = 5.5f;

         double dy = 5.55;

         string s = "Hello!";

         string s1 = "25";

         object obj = new Object ();

         // Далее идут методы класса, приводимые по ходу

        // описания примеров

    }

В набор данных класса входят скалярные данные арифметического типа, относящиеся к значимым типам, переменные строкового типа и типа object, принадлежащие ссылочным типам. Рассмотрим закрытый (private) метод этого класса — процедуру WhoIsWho с формальным аргументом класса Object. Процедура выводит на консоль переданное ей имя аргумента, его тип и значение. Вот ее текст:

/// <summary>

/// Метод выводит на консоль информацию о типе и

/// значении фактического аргумента. Формальный

/// аргумент имеет тип object. Фактический аргумент

/// может иметь любой тип, поскольку всегда

/// допустимо неявное преобразование в тип object.

/// </summary>

/// <param name="name"> — Имя второго аргумента</раrаm>

/// <param name="any"> — Допустим аргумент любого типа</раrаm>

void WhoIsWho(string name, object any)

{

      Console.WriteLine("type {0} is {1}, value is {2}",

           name, any.GetType(), any.ToString ());

}

Вот открытый (public) метод класса Testing, в котором многократно вызывается метод WhoIsWho с аргументами разного типа:

/// <summary>

/// получаем информацию о типе и значении

/// переданного аргумента — переменной или выражения /// </summary>

public void WhoTest()

{

     WhoIsWho("x",x);

     WhoIsWho("ux",ux);

     WhoIsWho("y",y);

     WhoIsWho("dy",dy);

     WhoIsWho ("s",s);

     WhoIsWho("11 + 5.55 + 5.5f",11 + 5.55 + 5.5f);

     obj = 11 + 5.55 + 5.5 f;

     WhoIsWho("obj",obj);

}

Заметьте, сущность any — формальный аргумент класса Object при каждом вызове — динамически изменяет тип, связываясь с объектом, заданным фактическим аргументом. Поэтому тип аргумента, выдаваемый на консоль, — это тип фактического аргумента. Заметьте также, что наследуемый от класса Object метод GetType возвращает тип FCL, то есть тот тип, на который отражается тип языка и с которым реально идет работа при выполнении модуля. В большинстве вызовов фактическим аргументом является переменная — соответствующее свойство класса Testing, но в одном случае передается обычное арифметическое выражение, автоматически преобразуемое в объект. Аналогичная ситуация имеет место и при выполнении присваивания в рассматриваемой процедуре.

На рис. 3.1 показаны результаты вывода на консоль, полученные при вызове метода WhoTest в приведенной выше процедуре Main класса Class1.

Рис. 3.1. Вывод на печать результатов теста WhoTest

Семантика присваивания. Преобразования между ссылочными и значимыми типами

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