using System;
using System.Collections;
namespace ComparableCar
{
// Этот вспомогательный класс используется для сортировки
// массива объектов Car по дружественному имени.
public class PetNameComparer : IComparer
{
// Проверить дружественное имя каждого объекта.
int IComparer.Compare(object o1, object o2)
{
if (o1 is Car t1 && o2 is Car t2)
{
return string.Compare(t1.PetName, t2.PetName,
StringComparison.OrdinalIgnoreCase);
}
else
{
throw new ArgumentException("Parameter is not a Car!");
// Параметр не является объектом типа Car!
}
}
}
}
Вспомогательный класс PetNameComparer может быть задействован в коде. Класс System.Array содержит несколько перегруженных версий метода Sort(), одна из которых принимает объект, реализующий интерфейс IComparer:
...
// Теперь сортировать по дружественному имени.
Array.Sort(myAutos, new PetNameComparer());
// Вывести отсортированный массив.
Console.WriteLine("Ordering by pet name:");
foreach(Car c in myAutos)
{
Console.WriteLine("{0} {1}", c.CarID, c.PetName);
}
...
Специальные свойства и специальные типы сортировки
Важно отметить, что вы можете применять специальное статическое свойство, оказывая пользователю объекта помощь с сортировкой типов Car по специфичному элементу данных. Предположим, что в класс Car добавлено статическое свойство только для чтения по имени SortByPetName, которое возвращает экземпляр класса, реализующего интерфейс IComparer (в этом случае PetNameComparer; не забудьте импортировать пространство имен System.Collections):
// Теперь мы поддерживаем специальное свойство для возвращения
// корректного экземпляра, реализующего интерфейс IComparer.
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})
public class Car : IComparable
{
...
// Свойство, возвращающее PetNameComparer.
public static IComparer SortByPetName
=> (IComparer)new PetNameComparer();}
Теперь в коде массив можно сортировать по дружественному имени, используя жестко ассоциированное свойство, а не автономный класс PetNameComparer:
// Сортировка по дружественному имени становится немного яснее.
Array.Sort(myAutos, Car.SortByPetName);
К настоящему моменту вы должны не только понимать способы определения и реализации собственных интерфейсов, но также оценить их полезность. Конечно, интерфейсы встречаются внутри каждого важного пространства имен .NET Core, а в оставшихся главах книги вы продолжите работать с разнообразными стандартными интерфейсами.
Резюме
Интерфейс может быть определен как именованная коллекция абстрактных членов. Интерфейс общепринято расценивать как поведение, которое может поддерживаться заданным типом. Когда два или больше число типов реализуют один и тот же интерфейс, каждый из них может трактоваться одинаковым образом (полиморфизм на основе интерфейсов), даже если типы определены в разных иерархиях.
Для определения новых интерфейсов в языке C# предусмотрено ключевое слово interface. Как было показано в главе, тип может поддерживать столько интерфейсов, сколько необходимо, и интерфейсы указываются в виде списка с разделителями-запятыми. Более того, разрешено создавать интерфейсы, которые являются производными от множества базовых интерфейсов.
В дополнение к построению специальных интерфейсов библиотеки .NET Core определяют набор стандартных (т.е. поставляемых вместе с платформой) интерфейсов. Вы видели, что можно создавать специальные типы, которые реализуют предопределенные интерфейсы с целью поддержки набора желательных возможностей, таких как клонирование, сортировка и перечисление.
Глава 9
Время существования объектов
К настоящему моменту вы уже умеете создавать специальные типы классов в С#. Теперь вы узнаете, каким образом исполняющая среда управляет размещенными экземплярами классов (т.е. объектами) посредством сборки мусора. Программистам на C# никогда не приходится непосредственно удалять управляемый объект из памяти (вспомните, что в языке C# даже нет ключевого слова наподобие delete). Взамен объекты .NET Core размещаются в области памяти, которая называется управляемой кучей, где они автоматически уничтожаются сборщиком мусора "в какой-то момент в будущем".
После изложения основных деталей, касающихся процесса сборки мусора, будет показано, каким образом программно взаимодействовать со сборщиком мусора, используя класс System.GC (что в большинстве проектов обычно не требуется). Мы рассмотрим, как с применением виртуального метода System.Object.Finalize() и интерфейса IDisposable строить классы, которые своевременно и предсказуемо освобождают внутренние неуправляемые ресурсы.
Кроме того, будут описаны некоторые функциональные возможности сборщика мусора, появившиеся в версии .NET 4.0, включая фоновую сборку мусора и ленивое (отложенное) создание объектов с использованием обобщенного класса System.Lazy<>. После освоения материалов данной главы вы должны хорошо понимать, каким образом исполняющая среда управляет объектами .NET Core.