СиППО (25-28, 42-45, 54-76) (987679), страница 8
Текст из файла (страница 8)
Shape q=new Shape(10,30);
q.Show_area();
//
Tri z1=new Tri(5,12);
z1.Show_area();
//
Shape w;
w=z1; // w будет указывать на объект класса Tri
w.Show_area(); // Tri.Show_area()
//
Square w1=new Square(5,12);
w1.Show_area();
//
w=w1; // w будет указывать на объект класса Square
w.Show_area(); //Square.Show_area()
}
}
}
Как видно из примера, указатель w имеет тип Shape, но он может указывать на любой наследник Shape. Выбор версии виртуального метода зависит от значения указателя на момент вызова, поэтому вызову w.Show_area(); соответствуют разные версии Show_area().
Абстрактные методы и классы
В C# существует возможность введения в базовом классе методов, а их реализацию оставить «на потом». Такие методы называют абстрактными. Абстрактный метод автоматически является и виртуальным, но писать это нельзя. Класс, в котором имеется хотя бы один абстрактный метод, тоже называется абстрактным и такой класс может служить только в качестве базового класса. Создать объекты абстрактных классов невозможно, потому что там нет реализации абстрактных методов. Чтобы класс- наследник абстрактного класса не был, в свою очередь, абстрактным (хотя и это не запрещено), там должны содержаться переопределения всех наследованных абстрактных методов.
Модифицируем приведенный выше пример.
namespace Virtual1
{
abstract class Shape
{ /* Создается абстрактный класс, наличие abstract обязательно! */
public int a,h;
public Shape (int x,int y)
{…}
public abstract void Show_area();// реализация не нужна – метод абстрактный, фиксируется лишь интерфейс метода
}
class Tri:Shape
{
int s;
public Tri(int x, int y) :base(x, y)
{…}
public override void Show_area()
{…}
}
class Square:Shape
{
int s;
public Square(int x, int y):base(x, y)
{…}
public override void Show_area()
{…}
}
class Class1
{
static void Main(string[] args)
{
Shape q; //указатель на абстрактный класс
// q=new Shape(4,6); это ошибка, нельзя создать объект
// абстрактного класса!
q = new Tri(10,20);
q.Show_area();
q = new Square(10,20);
q.Show_area();
Console.ReadLine();
} } }
Указатель на абстрактный класс может указывать на любой класс-наследник.
65. Класс List, создание и работа с классом List с нестандартными элементами
Представляет строго типизированный список объектов, доступных по индексу. Поддерживает методы для поиска по списку, выполнения сортировки и других операций со списками.
Класс List<T> является универсальным эквивалентом класса ArrayList. Он реализует универсальный интерфейс IList<T> с помощью массива, размер которого динамически увеличивается по мере необходимости.
Класс List<T> использует компаратор проверки на равенство и компаратор упорядочения.
Такие методы, как Contains, IndexOf, LastIndexOf и Remove, используют компаратор проверки на равенство для элементов списка. Компаратор проверки на равенство, используемый по умолчанию для типа T, определяется следующим образом. Если тип T реализует универсальный интерфейс IEquatable<T>, в качестве компаратора проверки на равенство используется метод Equals(T) этого интерфейса; в противном случае по умолчанию используется метод Object.Equals(Object).
Такие методы, как BinarySearch и Sort, используют компаратор упорядочения для элементов списка. Компаратор, используемый по умолчанию для типа T, определяется следующим образом. Если тип T реализует универсальный интерфейс IComparable<T>, в качестве компаратора по умолчанию используется метод CompareTo(T) этого интерфейса; в противном случае, если тип T реализует неуниверсальный интерфейс IComparable, в качестве компаратора по умолчанию используется метод CompareTo(Object) этого интерфейса. Если тип T не реализует ни один из интерфейсов, компаратор по умолчанию не определяется; в этом случае компаратор или делегат сравнения должен быть задан явным образом.
Сортировка списка List<T> не гарантируется. Необходимо отсортировать List<T> до выполнения операций (таких, как BinarySearch), для которых требуется отсортированный список List<T>.
Доступ к элементам этой коллекции осуществляется с помощью целочисленного индекса. Индексы в этой коллекции начинаются с нуля.
Список List<T> принимает null в качестве допустимого значения для ссылочных типов и разрешает дублирование элементов.
Делая выбор между классами List<T> и ArrayList, предлагающими сходные функциональные возможности, следует помнить, что класс List<T> в большинстве случаев обрабатывается быстрее и является потокобезопасным. Если в качестве типа T класса List<T> используется ссылочный тип, оба класса действуют идентичным образом. Однако если в качестве типа T используется тип значений, необходимо принять во внимание особенности, связанные с реализацией и упаковкой.
В следующем примере кода демонстрируются несколько свойств и методов универсального класса List<T>. С помощью конструктора по умолчанию создается список строк с емкостью по умолчанию. Выводится значение свойства Capacity, а затем с помощью метода Add добавляется несколько элементов. Выводится список этих элементов, а затем снова выводится значение свойства Capacity и вместе с ним — значение свойства Count, показывающее, что емкость увеличивается по мере необходимости.
С помощью метода Contains проверяется наличие некоторого элемента в списке, с помощью метода Insert в середину списка вставляется новый элемент, после чего снова выводится содержимое списка.
С помощью свойства по умолчанию Item (индексатор в C#) из списка извлекается элемент, с помощью метода Remove удаляется первый экземпляр дублированного элемента, добавленный ранее, и содержимое списка выводится вновь. Метод Remove всегда удаляет первый обнаруженный им экземпляр.
С помощью метода TrimExcess емкость уменьшается в соответствии с числом элементов, и выводятся значения свойств Capacity и Count. Если незадействованная емкость составляет менее 10% от общей емкости, изменение размера списка не требуется.
В заключение используется метод Clear для удаления всех элементов из списка, и выводятся значения свойств Capacity и Count.
using System;
using System.Collections.Generic;
public class Example
{
public static void Main()
{
List<string> dinosaurs = new List<string>();
Console.WriteLine("\nCapacity: {0}", dinosaurs.Capacity);
dinosaurs.Add("Tyrannosaurus");
dinosaurs.Add("Amargasaurus");
dinosaurs.Add("Mamenchisaurus");
dinosaurs.Add("Deinonychus");
dinosaurs.Add("Compsognathus");
Console.WriteLine();
foreach(string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
Console.WriteLine("\nCapacity: {0}", dinosaurs.Capacity);
Console.WriteLine("Count: {0}", dinosaurs.Count);
Console.WriteLine("\nContains(\"Deinonychus\"): {0}",
dinosaurs.Contains("Deinonychus"));
Console.WriteLine("\nInsert(2, \"Compsognathus\")");
dinosaurs.Insert(2, "Compsognathus");
Console.WriteLine();
foreach(string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
Console.WriteLine("\ndinosaurs[3]: {0}", dinosaurs[3]);
Console.WriteLine("\nRemove(\"Compsognathus\")");
dinosaurs.Remove("Compsognathus");
Console.WriteLine();
foreach(string dinosaur in dinosaurs)
{
Console.WriteLine(dinosaur);
}
dinosaurs.TrimExcess();
Console.WriteLine("\nTrimExcess()");
Console.WriteLine("Capacity: {0}", dinosaurs.Capacity);
Console.WriteLine("Count: {0}", dinosaurs.Count);
dinosaurs.Clear();
Console.WriteLine("\nClear()");
Console.WriteLine("Capacity: {0}", dinosaurs.Capacity);
Console.WriteLine("Count: {0}", dinosaurs.Count);
}
66. Принципы построения языка LINQ.
Базовыми единицами данных в LINQ являются последовательности и элементы. Последовательность – это любой объект, который реализует обобщенный интерфейс IEnumerable, а элемент – это просто элемент последовательности. В следующем примере массив строк names – это последовательность, а Tom, Dick и Harry – элементы:
string[] names = {“Tom”, “Dick”, “Harry” };
Такая последовательность называется локальной, потому что представляет локальную коллекцию объектов в памяти.
Оператор запроса – это метод, преобразующий последовательность. В типичном случае оператор запроса принимает входную последовательность и возвращает результат преобразования – выходную последовательность. В классе Enumerable из пространства имен System.Linq имеется около 40 операторов запроса, и все они реализованы как статические методы расширения. Они называются стандартными операторами запроса.
Запрос – это выражение, которое преобразует последовательности с помощью операторов запроса. Простейший запрос состоит из одной входной последовательности и одного оператора. Например, мы может применить оператор Where к строковому массиву и извлечь те его элементы, длина которых не меньше четырех символов:
string[] names = {“Tom”, “Dick”, “Harry” };
IEnumerable<string> filteredNames = System.Linq.Enumerable.Where (names, n => n.Length >= 4);
foreach (string n in filteredNames)