C#. Отношение между классами типа uses (класс использует другой класс). Примеры

Отношение между классами типа uses (класс использует другой класс). Примеры

Данная тема есть продолжением темы:


Содержание


1. Отношение между классами uses. Классификация

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

Согласно Б. Страуструпу (основатель языка C++) между двумя классами A, B можно установить следующие способы использования (uses) классом A класса B:

  • 1. Класс A использует имя класса B.
  • 2. Класс A использует класс B.
    • 2.1. Класс A вызывает функцию-член класса B.
    • 2.2. Класс A читает поле данных класса B.
    • 2.3. Класс A записывает поле данных класса B.
  • 3. Класс A создает объект типа B.
    • 3.1. Класс A выделяет память для автоматических объектов типа B.
    • 3.2. Класс A создает объект типа B с помощью оператора new.
  • 4. Класс A получает размеры класса B.

 

2. Пример. Класс A использует имя класса B

 

using System;
using static System.Console;

namespace ConsoleApp1
{
  // Взаимодействие между классами типа uses
  // Класс A использует имя класса B

  // Класс B - базовый класс
  class B
  {
    // Скрытая внутренняя переменная
    private int b = 25;

    // Виртуальный метод
    public virtual void Print(B refB)
    {
      WriteLine("Method B.Print():");
      WriteLine("b = {0}", refB.b);
    }
  }

  // Класс A - производный от класса B
  class A : B
  {
    // Скрытая внутренняя переменная
    private int a = 15;

    // В параметре метода класса A используется
    // имя класса B, как базового для реализации полиморфизма
    public override void Print(B refB)
    {
      WriteLine("Method A.Print():");
      base.Print(refB);
      WriteLine("a = {0}", a);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Создать экземпляр класса A
      A objA = new A();
      B objB = new B();

      // 2. Объявить ссылку на базовый класс B
      B ref;

      // 3. Направить ссылку ref на экземпляр класса A
      ref = obj;

      // 4. Вызвать виртуальный метод Print() через ссылку ref
      ref.Print(ref); // вызывается obj.Print(ref)

      // 5. Перенаправить ссылку на базовый класс B
      ref = obj;

      // 6. Вызвать виртуальный метод Print() через ссылку ref
      ref.Print(ref); // вызывается obj.Print(refB)
    }
  }
}

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

Method A.Print():
Method B.Print():
b = 25
a = 15
Method B.Print():
b = 25


 

3. Пример. Тип отношения uses. Класс A использует класс B

В примере демонстрируется несколько форм взаимодействия между классами, которые относятся к типу uses.

using System;
using static System.Console;

namespace ConsoleApp1
{
  // Взаимодействие между классами типа uses
  // Класс A использует класс B
  class B
  {
    public const double Pi2 = 6.28;
    public double Pi = 3.14;

    static public void MethodB()
    {
      WriteLine("B.MethodB()");
    }
  }

  class A
  {
    public void MethodA()
    {
      // 1. Вызов функции-члена класса B из класса A
      B.MethodB();

      // 2. Обращение к полю данных класса B из класса A
      WriteLine(B.Pi2);

      // 3. Запись поля данных класса B
      B objB = new B(); // создать экземпляр класса B
      objB.Pi = 3.141592; // записать поле данных
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Создать экземпляр класса A
      A objA = new A();

      // 2. Вызвать метод Method() класса A
      objA.MethodA();
    }
  }
}

Результат работы программы

B.MethodB()
6.28

 

4. Пример. Класс A динамически создает объект класса B

Данный пример более актуален для языка C++, поскольку в этом языке объект класса в методе можно создать двумя способами:

// Язык C++. Способ 1
B objB;

// Язык C++. Способ 2 - с помощью оператора new
B* pB = new B();

В языке C# все объекты (экземпляры) класса создаются динамически с помощью оператора new. Это связано с тем, что классы относятся к типу-ссылке а не к типу-значению. В случае с классами типы-ссылки содержат ссылки на экземпляр класса. Сама ссылка размещается в стеке, а экземпляр размещается в куче (heap). Поэтому, для размещения экземпляра нужно выделить память динамически.

Текст демонстрационной программы следующий.

using System;
using static System.Console;

namespace ConsoleApp1
{
  // Взаимодействие между классами типа uses
  // Класс A динамически создает объект класса B
  class B
  {
    // Внутреннее поле
    public int d;

    // Метод Show()
    public void Show()
    {
      WriteLine("d = {0}", d);
    }
  }

  class A
  {
    // Метод, который динамически создает объект класса B
    public void Demo()
    {
      WriteLine("Method A.Demo()");

      // 1. Создать экземпляр класса B динамически
      WriteLine("Creating instance objB.");
      B objB = new B();
      WriteLine("OK!");

      // 2. Заполнить значением объект класса B
      WriteLine("Fill with values objB.d.");
      objB.d = 330;
      WriteLine("OK!");
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Создать экземпляр класса A
      A objA = new A();

      // 2. Вызвать метод Demo() класса A
      objA.Demo();
    }
  }
}

Результат работы программы

Method A.Demo()
Creating instance objB.
OK!
Fill with values objB.d.
OK!

 

5. Пример. Класс A получает размеры класса B

В примере демонстрируется определение размеров экземпляра класса с помощью механизма сериализации.

using System;
using static System.Console;

// Необходимо для использования возможностей класса Stream
using System.IO;

// Необходимо для использования класса BinaryFormatter
using System.Runtime.Serialization.Formatters.Binary;

namespace ConsoleApp1
{
  // Исходный класс B, который содержит одно поле и один метод
  // Перед классом указывается, что класс будет сохраняться в памяти
  // (класс, который сериализуется)
  [Serializable]
  class B
  {
    public double x;

    void ShowX()
    {
      WriteLine("x = {0}", x);
    }
  }

  // Класс A, который содержит метод,
  // который определяет размер экземпляра класса B
  class A
  {
    // В методе создается экземпляр класса B,
    // и определяется его размер
    public void DemoSizeObjB()
    {
      // 1. Объявить внутренние переменные
      long size = 0; // размер экземпляра класса B
      B objB = new B(); // создать экземпляр

      // 2. Использование потока в памяти в двоичном виде
      // 2.1. Создать поток в памяти
      using (Stream s = new MemoryStream())
      {
        // 2.2. Создать экземпляр бинарного (двоичного)
        //      формата сериализации
        BinaryFormatter bf = new BinaryFormatter();

        // 2.3. Записать экземплряр objB в двоичном формате
        //     в память
        bf.Serialize(s, objB);

        // 2.4. Определить размер памяти,
        //       в который был записан экземпляр
        size = s.Length;

        // 2.5. Вывести размер на экран
        WriteLine("size = {0}", size);
      }
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Создать экземплряр класса A
      A objA = new A();

      // 2. Вызвать метод DemoSizeObjB()
      objA.DemoSizeObjB();
    }
  }
}

Результат работы программы

size = 129

 


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