Жизненный цикл объектов Создание… …объекта в области «управляемой кучи » (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!!!