Российский Государственный Технологический Университет им. К.Э. Циолковского
Опубликован: 02.03.2007 | Доступ: свободный | Студентов: 5677 / 802 | Оценка: 3.96 / 3.45 | Длительность: 27:04:00
ISBN: 978-5-9556-0086-4
Лекция 4:

Объекты

< Лекция 3 || Лекция 4: 123 || Лекция 5 >

this в конструкторе, деструкторе, методе, свойстве

Нестатический метод класса определяет индивидуальное поведение объекта и поэтому вызывается "от имени" данного объекта. В большинстве объектно-ориентированных языков программирования реализована возможность непосредственного обращения из нестатического метода (а также свойства) к объекту, который обеспечил выполнение кода данного метода или свойства. Аналогичная возможность обращения к объекту реализуется в теле нестатических конструкторов и деструктора.

В C# связь метода (свойства, конструктора, деструктора) с объектом обеспечивается первичным выражением (элементарным выражением языка) this. Это выражение не требует никакого дополнительного объявления, его тип соответствует классу, содержащему объявление данного метода. Он может использоваться в теле любого нестатического метода, конструктора и деструктора (о деструкторах — ниже) в любом классе или структуре, если только они содержат соответствующие объявления.

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

Если метод возвращает ссылку на объект, который вызвал данный метод, this можно использовать в качестве возвращаемого значения оператора return.

Для метода ToString все ссылки на объекты, представляющие данный класс, неразличимы. Следующий пример подтверждает тот факт, что this в нестатическом методе является всего лишь ссылкой на объект — представитель данного класса.

using System;

namespace XXX
{
class TEST
{
int x;
int y;
public string str;

public TEST(int xKey, int yKey) 
{
// В конструкторе this – это всегда ссылка
// на создаваемый объект
this.x = xKey; 
y = yKey;
str = "Ha-Ha-Ha";
}

public TEST f1(string strKey)
{
this.str = this.str + strKey + this.ToString();
// Здесь можно будет посмотреть,
// что собой представляет значение ссылки на объект.
return this; // А вот здесь без выражения this просто
// ничего не получается.
}     
}

class Program
{
static void Main(string[] args)
{
TEST t, tM;
t = new TEST(10, 10);
Console.WriteLine(t.str);
tM = t.f1(" from ");
t = new TEST(100, 100);
Console.WriteLine(t.str);
Console.WriteLine(t.ToString());
Console.WriteLine(tM.str);
Console.WriteLine(tM.ToString());
}
}
}
Листинг 4.2.

this в заголовке конструктора

Конструктор не вызывается. Передача управления конструктору осуществляется при выполнении операции new.

Ситуация: в структуре или классе объявляются различные версии конструкторов, специализирующиеся на создании объектов разной модификации. При этом все объявленные конструкторы вынуждены выполнять один и тот же общий перечень регламентных работ по инициализации объектов.

Для сокращения размера кода можно оставить ОДИН конструктор, выполняющий ВСЮ "черновую" обязательную работу по созданию объектов. Тонкую настройку объектов можно производить после выполнения кода конструктора, непосредственно вызывая соответствующие методы-члены. При этом методы вызываются именно ПОСЛЕ того, как отработает конструктор.

Можно также определить множество специализированных конструкторов, после выполнения которых следует вызывать дополнительный метод инициализации для общей "достройки" объекта.

И то и другое — некрасиво. Код получается сложный.

В C# реализован другой подход, который состоит в следующем:

  • определяется множество разнообразных специализированных конструкторов;
  • выделяется наименее специализированный конструктор, которому поручается выполнение обязательной работы;
  • обеспечивается передача управления из конструктора конструктору.

Вот так this в контексте конструктора обеспечивает в C# передачу управления от конструктора к конструктору. Таким образом, программист освобождается от необходимости повторного кодирования алгоритмов инициализации для каждого из вариантов конструктора.

Следующий фрагмент программного кода демонстрирует объявление нескольких конструкторов с передачей управления "золушке":

class Point2D
{
private float x, y;
public Point2D(float xKey, float yKey)
 {
Console.WriteLine("Point2D({0}, {1}) is here!", xKey, yKey);
// Какой-нибудь сложный обязательный
// код инициализации данных – членов класса.

int i = 0;
while (i < 100)
 {
x = xKey;
y = yKey;
i++;
 }	
 }

// А все другие конструкторы в обязательном порядке предполагают
// регламентные работы по инициализации значений объекта – и делают при этом
// еще много чего...
public Point2D():this(0,0)
 {
int i;
for (i = 0; i < 100; i++)
 {
// Хорошо, что значения уже проинициализированы! 
// Здесь своих проблем хватает.
 }

Console.WriteLine("Point2D() is here!");
 }

public Point2D(Point2D pKey):this(pKey.x, pKey.y)
 {
int i;
for (i = 0; i < 100; i++)
 {
// Здесь тоже заблаговременно  позаботились о значениях.
// Хорошо.
 }
Console.WriteLine("Point2D({0}) is here!", pKey.ToString());
 }
}
Листинг 4.3.

Уничтожение объектов в управляемой памяти. Деструктор

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

Однако сборщик мусора не способен освобождать другие типы ресурсов, например, соединения с базами данных и серверами (надо разъединять) и открытые файлы (надо закрывать).

Если соответствующие фрагменты кода, обеспечивающие освобождение этих ресурсов, разместить в специальном блоке операторов с заголовком, состоящем из имени класса с префиксом ' ~ ' и пустым списком параметров (в деструкторе), то время их освобождения совпадет со временем выполнения кода данного деструктора, который запускается при разрушении объекта сборщиком мусора. Однако время наступления этого события для конкретного объекта остается неопределенным. Порядок передачи управления деструкторам различных объектов в куче во время очистки памяти также неизвестен.

Простой пример, иллюстрирующий принципы функционирования управляемой памяти и работы деструктора:

using System;

namespace MemoryTest01
{

// Объекты этого класса регистрируют деятельность конструктора
// при создании объекта и деструктора при его уничтожении.
 public class MemElem
 {
  public static long AllElem = 0;
  long N = 0;
public MemElem(long key)
{
AllElem++;
N = key;
Console.WriteLine("{0} element was created. {1} in memory!", N, AllElem);
}


// Объявление деструктора.
~MemElem()
{
AllElem--;
Console.WriteLine("{0} was destroyed by GC. {1} in memory!", N, AllElem);
}
}

class Program
{

// Порождение объектов-представителей класса MemElem.
// Партиями по 50 штук.
// Периодичность активности GC (Garbage Cleaner) неизвестна.

static void Main(string[] args)
 {
    MemElem mem;
    string s;
    long N = 0;
    int i = 0;
    for ( ; ; )
    {
     Console.WriteLine("_________________________");
     Console.Write("x for terminate >> ");
     s = Console.ReadLine();
     if (s.Equals("x")) break;
     else N += i;
     for (i = 0; i < 50; i++)
     {
       mem = new MemElem(N+i);
     }
   }
 }
}
}
Листинг 4.4.

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

< Лекция 3 || Лекция 4: 123 || Лекция 5 >
kewezok kewezok
kewezok kewezok
Елена Шляхт
Елена Шляхт
Объясните плиз в чем отличие а++ от ++а
Почему результат разный?
int a=0, b=0;
Console.WriteLine(a++); //0
Console.WriteLine(++b); //1
a++;
++b;
Console.WriteLine(a); //2
Console.WriteLine(b); //2