Жизненный цикл объектов

advertisement
Жизненный цикл объектов
Создание…
…объекта в области
«управляемой кучи » (managed heap)
с помощью new.
Удаление…
.NET автоматически удалит
объект, когда он больше не
будет нужен
А как среда выполнения определяет, что
объект больше не нужен?????
.
У нас получится…
managed
heap
Car car1 = new Car();
Car car2 = new Car();
Car car3 = new Car();
c1
c2
c3
Empty…
Завершение ссылки на объект
GC (GarbageCollector) или СборщикМусора работает автоматически,
НО! Всегда ли это хорошо?
Вообще говоря, нет…
Для таких случаев предусмотрена возможность реализации в нашем
классе метода System.Object.Finalize().
НУЖНО в наш класс ввести «деструктор»:
public class Car :Object
{
~Саг()
{ //Закрывайте все открытые
//объектом ресурсы!
//Далее в С# будет автоматически
//вызван базовый метод Finalize()
}
}
Car c1 = new Car();
Ссылка на c1
попадает в очередь
завершения
IDisposable
Интерфейс, созданный для обеспечения единообразия
методов Dispose()
public interface IDisposable
{
public void Dispose();
}
Про интерфейсы
как таковые
поговорим позже…
Применим его для класса Car:
public class Car :IDisposable
{
public void Dispose()
{
//...Закрываем открытые
// внутренние ресурсы
}
}
Возможно сочетание
с пользовательским
деструктором
А вот и Сборщик Мусора…
GC – как и все остальное в C#, это объект!..
…класса System.GC
Метод, свойство
Что делает?
Collect([int numGen])
Запускает GC [для конкретного
поколения]
GetGeneration()
Возвращает поколение
MaxGeneration
Возвращает макс поколение,
поддерживаемое данной системой
ReRegisterForFinalize()
Отменяет действие след. функции
SupressFinalize()
Устанавливает флаг запрещения
завершения для объектов
GetTotalMemory(boolean bUpdate)
Количество байт, занятое в куче
Примеры…
public class Саг :IDisposable
{
~Car()
{
Dispose();
}
public void Dispose()
{
//Закрываем открытые
//внутренние
//ресурсы
GС.SupressFinalize (this);
}
}
public class GCApp
{
public static int Main(string [] args)
{
Console.WriteLine(“Heap memory in use:{0}",
GC.GetTotalMemory(false).ToStrlng());
Саг c1,с2,сЗ,с4;
c1 = new Car ("Car one“,40,10);
c2 = new Car ("Car two",70,5);
c3 = new Car ("Car three“,200,100);
c4 = new Car (“Car four",140,80);
//Применяем метод Dispose() к некоторым
//объектам. В результате завершение
//для них будет отменено
c1.Dispose();
c3.Dispose();
//Вызываем метод Finalize() для
//объектов,остающихся в очереди
//завершений
GC.Collect();
return 0;
}
}
Подробнее о поколениях
Когда сборщик мусора помечает объекты для удаления он не
проверяет все объекты подряд (это может занять много
времени)…
Для этого используются поколения, которые задают своего рода
приоритет в работе GC.
Поколение
Кто попадает?
1
Объекты, еще не прошедшие проверку
GC
2
Объекты, прошедшие 1 проверку GC, но
еще не удаленные(было достаточно
места в куче?)
3
Объекты, которые пережили > 1
проверки GC
Пример…
public static int Main(string [ ] args)
{
Console.WriteLine(“Heap memory in use:“ +GC.GetTotalMemory(false).ToString());
Саr c1,с2,сЗ,с4;
c1 =new Car(“Car one",40,10);
c2 =new Car(“Car two“,70,5);
сЗ =new Car(“Car three”,200,100);
c4 =new Car(“Car four“,140,80);
Console.WriteLine(“C1 is gen {0}“,GC.GetGeneration(c1)};
Console.WriteLine(“C2 is gen {0}”,GC.GetGeneration(c2));
Console.WriteLine(“CS is gen {0}",GC.GetGeneration(c3));
Console.WriteLine(“C4 is gen {0}“,GC.GetGeneration(c4));
//Удаляем вручную некоторые объекты
c1.Dispose();
c2.Dispose();
GC.Collect(0);
Console.WriteLine(“C1 is gen {0}".GC.GetGeneration(c1));
Console.WriteLine("C2 is gen {0}",GC.GetGeneration(c2));
Console.WriteLine(“C3 is gen {0}",GC.GetGeneration(c3));
Console.WriteLine("C4 is gen {0}",GC.GetGeneration(c4));
Console.WriteLine(“Heap memory in use:"+GC.GetTotalMemory(false).ToString());
return 0;
}
Итак…
Теперь мы знаем о жизненном цикле объектов и о сборщике
мусора ВСЕ (по крайней мере, что-то мы теперь знаем
точно…)!!!
Но тем не менее, не стоит использовать все известные нам
методы только потому, что мы их знаем!
GC будет устраивать нас в большинстве случаев, а
определять логику нашего пользовательского деструктора С#
или реализовывать интерфейс IDisposable для
принудительного освобождения ресурсов объектом нашего
класса нужно только в случаях необходимости.
продолжение следует…
Интерфейсы
В этой главе…
Создание и реализация
интерфейсов
Получение ссылок на
интерфейсы
Создание иерархий
интерфейсов
+ стандартные интерфейсы .Net
Интерфейс — это набор семантически связанных
абстрактных членов.
public interface IDegree
{
byte GetNumberOfPoints();
//Автоматически (неявным образом) этот член
//интерфейса становится абстрактным
}
Преимущества:
1) Множественное наследование;
2) 100% гарантия отсутствия неабстрактных методов и
членов;
3) Нет реализаций по умолчанию;
Очевидно, что создать «объект интерфейса» нельзя…
Примеры:
public class Triangle :Shape,IDegree
{
public Triangle(){ }
public Triangle(string name):base(name){ }
public override void Draw();
Console.WriteLine("Drawing {0} the Triangle“,PetName}:
public byte GetNumberOfPoints()
{
return 3;
}
}
NB:
В классе либо должны быть реализованы все методы
данного интерфейса, либо этот интерфейс вообще не
реализуется — половинчатого решения быть не может!
Получение ссылок на интерфейс
1
НО!
2
3
Triangle tr =new Triangle(“first");
IDegree itfDg = (IDegree)tr;
Console.WriteLine(itfDg.GetNumberOfPoints());
Circle cr =new Circle(“circ1");
IDegree itfDg = (IDegree)cr;
Console.WriteLine(itfDg.GetNumberOfPoints());
Triangle tr =new Triangle(“second");
IDegree itfDg2:
itfDg2 = tr as IDegree;
if(itfDg2 != null)
Console.WriteLine(itfDg2.GetNumberOfPoints());
else
Console.WriteLine("OOPS! No degrees...");
Triangle tr =new Triangle();
if(tr is IDegree)
Console.WriteLine(tr.GetNumberOfPoints());
else
Console.WriteLine(“OOPS! No degree...”);
InvalidCastException
Интерфейсы как параметры
public interface IDraw3D
{
void Draw3D();
}
public class Circle :Shape,IDraw3D
{
public void Draw3D()
{
Console.WriteLine(“Drawing Circle in
3D!");
}
}
public class ShapesApp
{
//Будут нарисованы все
//объекты,поддерживающие интерфейс
//IDraw3D
public static void
DrawThisShapeIn3D(IDraw3D itf3d)
{
itf3d.Draw3D();
}
public static int Main(string [] args)
{
Shape [] s ={new Circle(),
new Triangle(),
new Circle(“JoJo")};
for (int i=0;i<s.Length;i++)
{
if (s[i] is IDraw3D)
DrawThisShapeln3D((IDraw3D)s [i]);
return 0;
}
}
}
Явная реализация интерфейса
Теперь сделаем тот же интерфейс, но назовем метод
Draw() вместо Draw3D (возникнут ли у нас проблемы? Ведь
есть же и базовый метод Draw…)
public interface IDraw3D
{
void Draw();
}
public class Line :Shape,IDraw3D
{
public override void Draw()
{
Console.WriteLine(“Drawing a line..."};
}
}
А теперь кусочек кода…
//Вызываем Line.Draw()
Line myLine =new Line();
myLine.Draw();
//Вызываем Line.Draw() еще раз. но уже по-другому
(IDraw3D)myLine.Draw();
И что мы
получим в
результате?
А получим мы вызов одной и той же функции!
Чтобы такого не происходило и используется явная реализация
интерфейса(explicit interface implementation). Вот как это работает…
public class Line :Shape,IDraw3D
{
//реализация интерфейса
//!!!!!!!!
//здесь нет public!!!!
void IDraw3D.Draw()
{
Console.WriteLine(“Drawing a 3D line...");
}
//замещение базовой функции
public override void Draw()
{
Console.WriteLine(“Drawing a line...");
}
}
Создание иерархий интерфейсов
В отличии от классов, у интерфейса может быть несколько
базовых интерфейсов
public interface IDraw
{
void Draw();
}
public interface IDraw2 :IDraw
{
void DrawToPrinter();
}
public interface IDraw3 :IDraw2
{
void DrawToMetaFile();
}
Если мы хотим, чтобы наш класс поддерживал все эти
методы, то он должен производиться от IDraw3,
пример следует…
public class Superlmage :IDraw3
{
//явная реализация интерфейсов
// (мы же помним что это?;])
void IDraw.Draw()
{
//Обычный вывод на экран
}
void IDraw2.DrawToPrinter()
{
//Вывод на принтер
}
void IDraw3.DrawToMetafile()
{
//Вывод в метафайл
}
}
Пример использования(кратко):
.
.
SuperImage si=new SuperImage();
IDraw itfDraw=(IDraw)si;
itfDraw.Draw();
If(itfDraw is IDraw3)
{
(IDraw3)itfDraw.DrawToMetaFilе();
(IDraw3)itfDraw.DrawToPrinter();
}
Теперь рассмотрим наш последний пример, в котором все те же
возможности, но уже используя множественное наследование
интерфейсов…
Итак… Пусть интерфейсы будут «простыми» (без наследования)
public interface IDraw
{
void Draw();
}
public interface IDraw2
{
void DrawToPrinter();
}
public interface IDraw2
{
void DrawToMetaFile();
}
Тогда…Наш класс
станет таким
public class Superlmage :IDraw,IDraw2,IDraw3
{
void IDraw.Draw()
{
//Обычный вывод на экран
}
void IDraw2.DrawToPrinter()
{
//Вывод на принтер
}
void IDraw3.DrawToMetafile()
{
//Вывод в метафайл
}
}
И, наконец…
…the end!!!
Download