Шаг 157.
Язык программирования C#. Начала.
Абстрактные классы и интерфейсы. Знакомство с интерфейсами (продолжение)

    На этом шаге мы рассмотрим небольшой пример, иллюстрирующий использование интерфейсов.

    Для начала мы рассмотрим небольшой пример, в котором описывается интерфейс, а затем этот интерфейс реализуется в классе. Обратимся к программе, приведенной ниже.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace pr157_1
{
    // Интерфейс: 
    interface MyInterface {
        // Объявление методов: 
        void show(); 
        void setNum(int n); 
        int getNum();
        // Объявление свойства: 
        int number { 
            get; 
            set;
        }
        // Объявление индексатора: 
        int this[int k] { 
            get;
        }
    }

    // Класс реализует интерфейс: 
    class MyClass: MyInterface {
        // Закрытое целочисленное поле: 
        private int num;
        // Конструктор с одним аргументом:
        public MyClass(int n) {
            // Присваивание значения свойству: 
            number = n;
            // Вызывается метод из интерфейса: 
            show();
        }
        // Описание метода из интерфейса: 
        public void show() {
            // Отображение значения свойства: 
            Console.WriteLine("Свойство number = " + number);
        }
        // Описание метода из интерфейса: 
        public void setNum(int n) {
            // Присваивание значения полю: 
            num = n;
        }
        // Описание метода из интерфейса: 
        public int getNum() {
            // Значение поля: 
            return num;
        }
        // Описание свойства из интерфейса: 
        public int number {
            // Аксессор для считывания значения: 
            get {
                // Вызывается метод из интерфейса: 
                return getNum();
            }
            // Аксессор для присваивания значения: 
            set {
                // Вызывается метод из интерфейса: 
                setNum(value);
            }
        }
        // Описание индексатора из интерфейса: 
        public int this[int k] {
            // Аксессор для считывания значения: 
            get {
                // Локальная переменная: 
                int r = number;
                // "Отбрасывание" цифр в десятичном представлении числа: 
                for(int i = 0; i < k; i++) { 
                    r /= 10;
                }
                // Результат: 
                return r % 10;
            }
        }
    }

    // Класс с главным методом: 
    class Program
    {
        // Главный метод:
        static void Main()
        {
            // Целочисленная переменная: 
            int m = 9;
            // Создание объекта:
            MyClass obj = new MyClass(12345);
            // Индексирование объекта: 
            for(int i = 0; i <= m; i++) {
                Console.Write("|" + obj[m-i]);
            }
            Console.WriteLine("|");
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

    Результат выполнения программы такой:


Рис.1. Результат выполнения программы

    В программе мы описали интерфейс с названием MyInterface. В этом интерфейсе объявлены три метода (метод show() без аргументов и не возвращающий результат; метод getNum() без аргументов с целочисленным результатом; и метод setNum() с целочисленным аргументом и не возвращающий результат), целочисленное свойство number (доступное для считывания и записи) и индексатор с целочисленным индексом (доступен для считывания).


То, что мы объявили в интерфейсе индексатор только с get-аксессором, означает, что при реализации индексатора в классе для индексатора должен быть описан get-аксессор. Но мы можем описать для индексатора и set-аксессор. А вот если бы мы определяли индексатор, унаследованный из базового абстрактного класса, то описывать нужно было бы только те аксессоры, которые "заявлены" для индексатора в абстрактном классе.

    Класс MyClass реализует интерфейс MyInterface. В классе есть закрытое целочисленное поле num. Метод setNum() описан так, что переданный методу аргумент присваивается значением полю num. Метод getNum() результатом возвращает значение num.


Методы, объявленные в интерфейсе, по умолчанию считаются открытыми. Поэтому в классе они описываются с ключевым словом public. Это же замечание относится к свойствам и индексаторам.

    Целочисленное свойство number описано так, что при считывании значения свойства вызывается метод getNum(), который в свою очередь возвращает результатом значение поля num. При присваивании значения свойству number вызывается метод setNum(), аргументом которому передается присваиваемое свойству значение (определяется параметром value). В результате это значение присваивается полю num.

    Метод show() описан таким образом, что при его вызове отображается значение свойства number.

    В конструкторе класса сначала командой

  number = n;
свойству number присваивается в качестве значения аргумент n конструктора. После этого вызывается метод show(). Таким образом, при создании объекта класса MyClass в консольном окне появляется сообщение с информацией о значении свойства number.

    Индексатор в классе описан таким образом, что при индексировании объекта целочисленным индексом результатом возвращается цифра в десятичном представлении числа. Число в данном случае - это значение свойства number, и оно же - значение поля num. Индекс определяет позицию (разряд), на которой находится возвращаемая цифра в числе. Для вычисления результата в теле get-аксессора целочисленной переменной r присваивается значение свойства number, после чего запускается цикл, в котором на каждой итерации командой

  r /= 10;
в десятичном представлении числа, записанного в переменную r, отбрасывается последняя цифра. Количество итераций цикла определяется значением индекса k. В итоге цифра, которая нас интересует, окажется на последней позиции. Эту цифру мы вычисляем командой r%10 как остаток от деления на 10.

    В главном методе программы командой

  MyClass obj = new MyClass(12345);
создается объект obj класса MyClass. При этом через цепочки вызовов задействованы практически все методы и свойство number, которые описаны в классе MyClass. Пример индексирования объекта представлен в цикле, с помощью которого отображается десятичное представление числа, являющегося значением поля num объекта obj. Количество отображаемых разрядов превышает разрядную длину числа, поэтому старшие разряды заполнены нулями.

    На следующем шаге мы закончим изучение этого вопроса.




Предыдущий шаг Содержание Следующий шаг