Основы программирования — второй семестр 08-09; Михалкович С.С.; VIII часть — различия между версиями
Juliet (обсуждение | вклад) (→Вводные понятия) |
Admin (обсуждение | вклад) (→Методы расширения и интерфейсы) |
||
(не показано 26 промежуточных версий 4 участников) | |||
Строка 116: | Строка 116: | ||
Base = class | Base = class | ||
public | public | ||
− | procedure Method1; virtual; | + | procedure Method1; virtual; begin end; |
− | procedure Method2; virtual; | + | procedure Method2; virtual; begin end; |
− | procedure Method3; virtual; | + | procedure Method3; virtual; begin end; |
end; | end; | ||
Строка 187: | Строка 187: | ||
:Возвращает объект типа <tt>System.Type</tt>, который характеризует тип данного объекта. | :Возвращает объект типа <tt>System.Type</tt>, который характеризует тип данного объекта. | ||
− | ''<u>Пример</u>.'' | + | ''<u>Пример 1</u>.'' |
<source lang="Delphi"> | <source lang="Delphi"> | ||
var i: integer := 5; | var i: integer := 5; | ||
Строка 246: | Строка 246: | ||
[[Переопределение методов Equals и ToString на примере классов Person и Student | Полный текст новой версии классов Person и Student]] | [[Переопределение методов Equals и ToString на примере классов Person и Student | Полный текст новой версии классов Person и Student]] | ||
+ | |||
+ | ''<u>Пример 2</u>. Родословная переменной.'' | ||
+ | <source lang="Delphi"> | ||
+ | uses University; | ||
+ | |||
+ | procedure PrintLineage(o: object); | ||
+ | begin | ||
+ | var t := o.GetType; | ||
+ | writeln(t.Name); | ||
+ | |||
+ | repeat | ||
+ | t := t.BaseType; | ||
+ | if t = nil then | ||
+ | exit; | ||
+ | writeln(t.Name); | ||
+ | until false; | ||
+ | end; | ||
+ | |||
+ | begin | ||
+ | var s := new SeniorStudent('Иванов', 20, 4, 11, new Teacher('Петров'), Magister); | ||
+ | PrintLineage(s); | ||
+ | end. | ||
+ | </source> | ||
+ | |||
+ | '''Замечание.''' Полиморфизм обеспечивает изменчивость в будущем ''уже откомпилированного'' кода за счет создания подклассов. | ||
=== Цепочка виртуальности и её разрыв === | === Цепочка виртуальности и её разрыв === | ||
+ | Пусть у нас есть следующая иерархия наследования: | ||
+ | '''A''' <— '''B''' <— '''C''' | ||
+ | procedure Print; '''virtual'''; procedure Print; '''override'''; procedure Print; '''override'''; | ||
+ | |||
+ | :Говорят, что методы <tt>A.Print</tt>, <tt>B.Print</tt> и <tt>C.Print</tt> '''завязаны в цепочку виртуальности'''. | ||
+ | |||
+ | Унаследуем от класса <tt>C</tt> класс <tt>D</tt> следующим образом: | ||
+ | '''D''' (C) | ||
+ | procedure Print; | ||
+ | Будет предупреждение: «''Укажите '''override''' или '''reintroduce'''''». | ||
+ | |||
+ | Ключевое слово '''<tt>reintroduce</tt>''' служит для ''разрыва'' цепочки виртуальности. <br /> | ||
+ | Если написать: | ||
+ | ... '''reintroduce'''; '''virtual'''; | ||
+ | то это будет началом ''новой'' цепочки виртуальности. | ||
=== Алгоритм поиска в цепочке виртуальности === | === Алгоритм поиска в цепочке виртуальности === | ||
+ | |||
+ | == Интерфейсы == | ||
+ | Интерфейс - это специальным образом оформленный легковесный класс, задающий набор требований, которые должен реализовывать обычный класс. | ||
+ | |||
+ | В интерфейс входят заголовки методов и свойства с указанием доступа. Интерфейсы близки к абстрактным классам, но не могут содержать поля. | ||
+ | |||
+ | Все методы в интерфейсах считаются публичными, уровень доступа указывать не надо. | ||
+ | |||
+ | '''Пример.''' | ||
+ | <source lang="Delphi"> | ||
+ | interface IPrintable | ||
+ | procedure Print; | ||
+ | procedure Println; | ||
+ | end; | ||
+ | |||
+ | interface ICoords<T> | ||
+ | property X: T read; | ||
+ | property Y: T read; | ||
+ | end; | ||
+ | |||
+ | interface ICloneable // стандартный, из пространства имен System | ||
+ | procedure Clone; | ||
+ | end; | ||
+ | </source> | ||
+ | |||
+ | Интуитивно: интерфейсы - это роли, которые играют объекты классов в разных ситуациях. | ||
+ | |||
+ | Один и тот же класс может реализовывать несколько интерфейсов, один и тот же интерфейс может реализовываться совершенно различными классами. | ||
+ | |||
+ | === Реализация интерфейсов === | ||
+ | <source lang="Delphi"> | ||
+ | type Student = class(Person,ICloneable,IPrintable) | ||
+ | ... | ||
+ | function Clone: Object; | ||
+ | begin | ||
+ | Result := new Student(Name,Age,Course,Group); | ||
+ | end; | ||
+ | procedure Print; | ||
+ | begin | ||
+ | ... | ||
+ | end; | ||
+ | procedure Println; | ||
+ | begin | ||
+ | ... | ||
+ | end; | ||
+ | end; | ||
+ | type List<T> = class(ICloneable,IPrintable) | ||
+ | ... | ||
+ | end; | ||
+ | </source> | ||
+ | |||
+ | Класс наследуется от одного класса, но может реализовывать несколько интерфейсов. | ||
+ | |||
+ | Все методы и свойства интерфейса, реализуемые классом, должны быть объявлены публичными | ||
+ | |||
+ | Совершенно разнородные классы могут реализовывать одинаковые интерфейсы. | ||
+ | |||
+ | === Совместимость по := и операции is as для интерфейсов === | ||
+ | Для интерфейсов работают те же правила совместимости по присваиванию, что и для обычных классов: | ||
+ | # Если класс реализует интерфейс, то переменной типа интерфейс можно присвоить объект этого класса | ||
+ | # Можно использовать конструкции вида p is MyClass, p as MyClass, где p - переменная типа интерфейс | ||
+ | |||
+ | === Интерфейсы и полиморфизм === | ||
+ | Все методы интерфейсов, реализуемые классами, являются виртуальными - для этого необязательно использовать virtual | ||
+ | |||
+ | Если virtual не используется, то цепочка виртуальности прерывается, если используется - продолжается: | ||
+ | |||
+ | <source lang="Delphi"> | ||
+ | type IShape = interface(ICoords<integer>) | ||
+ | procedure Draw; | ||
+ | procedeure Hide; | ||
+ | procedeure MoveTo(x,y: integer); | ||
+ | procedeure MoveOn(dx,dy: integer); | ||
+ | end; | ||
+ | Shape = class(IShape) | ||
+ | ... | ||
+ | procedure Draw; virtual; | ||
+ | procedeure Hide; virtual; | ||
+ | end; | ||
+ | </source> | ||
+ | |||
+ | === Иерархия графических фигур - классический пример использования полиморфизма === | ||
+ | |||
+ | |||
+ | === Абстрактные методы и классы === | ||
+ | Сделать Shape абстрактным | ||
+ | |||
+ | === Полиморфные контейнеры === | ||
+ | List<Shape> | ||
+ | Цикл по полиморфному контейнеру | ||
+ | # с вызовом виртуального метода | ||
+ | # с вызовом индивидуального метода и использованием as | ||
+ | # с вызовом индивидуального метода и использованием GetType | ||
+ | |||
+ | === Интерфейсы и наследование === | ||
+ | Реализация интерфейсов является одной из форм наследования. В этой форме всегда выполняется принцип подстановки. | ||
+ | Недостатки: все методы необходимо реализовывать с нуля | ||
+ | Достоинства: нет "груза прошлого" - тяжеловесной реализации базовых классов, которая уже не нужна в производных. Пример с наследованием с ограничениями (круг от эллипса): реализация эллипса тяжеловесна, при реализации круга мы используем лишь часть этих возможностей. | ||
+ | |||
+ | === Стандартные интерфейсы .NET === | ||
+ | |||
+ | Пример 1. Интерфейс IComparable и его использование. | ||
+ | <source lang="Delphi"> | ||
+ | uses System; | ||
+ | |||
+ | type Student = class(Person,IComparable<Student>) | ||
+ | ... | ||
+ | public | ||
+ | function CompareTo(o: Student): integer; | ||
+ | begin | ||
+ | var s := Student(o); | ||
+ | if (Course < s.Course) or (Course = s.Course) and (Group < s.Group) then | ||
+ | Result := -1 | ||
+ | else if (Course = s.Course) and (Group = s.Group) then | ||
+ | Result := 0 | ||
+ | else Result := 1; | ||
+ | end; | ||
+ | end; | ||
+ | </source> | ||
+ | |||
+ | Пример 2. Интерфейс IComparer и его использование. | ||
+ | |||
+ | Пример 3. Написание MinElem<T>(a: array of T); where T: IComparable<T> | ||
+ | |||
+ | === Методы расширения === | ||
+ | integer.Print | ||
+ | write(Self) | ||
+ | |||
+ | === Методы расширения и интерфейсы === | ||
+ | <source lang="Delphi">uses System.Collections.Generic; | ||
+ | |||
+ | function Identity(i: integer): integer; | ||
+ | begin | ||
+ | Result := i; | ||
+ | end; | ||
+ | |||
+ | procedure Print<T>(ie: IEnumerable<T>); | ||
+ | begin | ||
+ | foreach i: integer in ie do | ||
+ | write(i,' '); | ||
+ | writeln; | ||
+ | end; | ||
+ | |||
+ | begin | ||
+ | var a: array of integer := (1,5,3,10,7,4,8,3,11,2,2,3,4); | ||
+ | var a1: array of integer := (2,5,7,4,11,9,23,34); | ||
+ | writeln(a.All(Odd)); | ||
+ | writeln(a.Any(Odd)); | ||
+ | writeln(a.Average()); | ||
+ | writeln(a.Contains(10)); | ||
+ | writeln(a.Count()); | ||
+ | writeln(a.Distinct().Count()); | ||
+ | writeln(a.ElementAt(2)); | ||
+ | writeln(a.ElementAtOrDefault(100)); | ||
+ | |||
+ | Print(a.Concat(a1)); | ||
+ | Print(a.Distinct()); | ||
+ | Print(a.Except(a1)); | ||
+ | Print(a.Intersect(a1)); | ||
+ | Print(a.Union(a1)); | ||
+ | Print(a.Skip(5)); | ||
+ | Print(a.Take(5)); | ||
+ | Print(a.TakeWhile(Odd)); | ||
+ | Print(a.Where(Odd)); | ||
+ | writeln(a.Where(Odd).Average()); | ||
+ | |||
+ | writeln(a.Last()); | ||
+ | writeln(a.Max()); | ||
+ | writeln(a.Min()); | ||
+ | var ff: System.Func<integer,integer> := f; | ||
+ | a.Select(Identity); // !! | ||
+ | writeln(a.SequenceEqual(a)); | ||
+ | writeln(a.Sum()); | ||
+ | a.OrderBy(Identity); | ||
+ | end.</source> | ||
+ | |||
+ | === Лямбды === | ||
+ | |||
+ | <source lang="Delphi">uses Arrays; | ||
+ | |||
+ | var a: array of integer := (1,2,3,5,7); | ||
+ | |||
+ | begin | ||
+ | a := a.Select((x: integer)->x*x).ToArray(); | ||
+ | a.Writeln; | ||
+ | end. | ||
+ | </source> | ||
+ | |||
+ | <source lang="Delphi">uses Core,Arrays; | ||
+ | |||
+ | var a: array of string := ('Hello','Abracadabra','Hi','Good','Bye'); | ||
+ | |||
+ | begin | ||
+ | var res := a.OrderBy((x: string) -> x.Length); | ||
+ | res.ToArray().Writeln(); | ||
+ | end.</source> | ||
+ | |||
+ | <source lang="Delphi"> writeln(a.First((x: integer) -> x>5)); </source> | ||
+ | [[Категория:Основы программирования]] |
Текущая версия на 23:59, 27 мая 2012
Содержание
- 1 Полиморфизм и виртуальные методы
- 2 Интерфейсы
- 2.1 Реализация интерфейсов
- 2.2 Совместимость по := и операции is as для интерфейсов
- 2.3 Интерфейсы и полиморфизм
- 2.4 Иерархия графических фигур - классический пример использования полиморфизма
- 2.5 Абстрактные методы и классы
- 2.6 Полиморфные контейнеры
- 2.7 Интерфейсы и наследование
- 2.8 Стандартные интерфейсы .NET
- 2.9 Методы расширения
- 2.10 Методы расширения и интерфейсы
- 2.11 Лямбды
Полиморфизм и виртуальные методы
Вводные понятия
Для объектно-ориентированного программирования часто приводят следующую формулу:
ООП = инкапсуляция + наследование + полиморфизм
Рассмотрим последнюю часть этой формулы - полиморфизм.
- Полиморфизм дословно означает многообразие форм.
Более точно, полиморфизм — это способность родственных классов выполнять действия с одинаковыми именами сходным образом.
Пример.
Есть класс
Студент Готовиться_к_экзамену()
И два его наследника:
Хороший_студент Готовиться_к_экзамену()
и
Плохой студент Готовиться_к_экзамену()
Действие Готовиться_к_экзамену() они выполняют по-разному.
Рассмотрим следующий код:
var p: Person;
p := new Student('Иванов', 17, 1, 11);
p.Print();
Вопрос: какой метод Print вызовется?
Ответ: В разных языках программирования вызовутся Print разных классов:
- в таких языках, как Java, Eiffel — Student.Print
- а в C++, C#, PasacalABC.NET — Person.Print
Т.о. в PascalABC.NET вызовется метод Person.Print, но, хотелось бы, чтобы вызывался метод Student.Print.
- Если решение о том, какой метод вызывать, принимается на этапе компиляции (рано), то связывание имени метода с конкретным кодом называется ранним связыванием.
- Если же решение о том, какой метод вызывать, принимается на этапе выполнения программы (поздно), то связывание имени метода с конкретным кодом называется поздним связыванием.
Позднее связывание осущесвляется с методом того класса, на который ссылается переменная в процессе выполнения программы.
Итак, в PascalABC.NET по умолчанию реализовано раннее связывание.
Позднее связывание и виртуальные методы
Чтобы обеспечить позднее связывание в языке Pascal, соответствующие методы надо сделать виртуальными в базовом классе.
type
Person = class
...
public
...
procedure Print; virtual;
begin
WriteFormat('Имя: {0} Возраст: {1} ',
fName, fAge);
end;
end;
Student = class(Person)
...
public
procedure Print; override;
begin
inherited Print;
WriteFormat('Курс: {0} Группа: {1} ',
fCourse, fGroup);
end;
end;
При переопределении виртуального метода в классе-потомке используется ключевое слово override.
Примечание. Переопределяющий виртуальный метод должен иметь те же параметры и тот же тип возвращаемого значения.
Вернемся к рассмотренному ранее коду:
var p: Person;
p := new Student('Иванов', 17, 1, 11);
p.Print();
Теперь решение о том, какой метод вызывать, будет отложено до этапа выполнения, и будет вызвано Print того класса, на объект которого ссылается переменная в текущий момент (в данном случае — для Student).
Вызов виртуального метода осуществляется немного медленнее обычного метода.
Полиморфизм в объектно-ориентированных программирования реализуется через механизм виртуальных методов.
- Переменная базового класса, содержащая виртуальные методы, называется полиморфной переменной.
Она имеет статический тип (заявленный при объявлении) и динамический (тип объекта, на который она ссылается в данный момент выполнения программы).
Замечание. Обычная подпрограмма также может быть полиморфной.
Пример.
procedure Print(p: Person);
begin
p.Print(); // обращение полиморфизма
end;
...
Print(new Student(...));
- Обычная подпрограмма называется полиморфной, если она содержит хотя бы один полиморфный параметр.
Виртуальные методы как блоки замены кода
Рассмотрим следующий полиморфный метод:
procedure polymorph(p: Base);
begin
p.Method1;
p.Method2;
p.Method3;
end;
Напишем класс StudentInSession, унаследовав его от Base:
procedure polymorph(p: Base);
type
Base = class
public
procedure Method1; virtual; begin end;
procedure Method2; virtual; begin end;
procedure Method3; virtual; begin end;
end;
StudentInSession = class(Base)
public
procedure Method1; override;
begin
writeln('Sleep');
end;
procedure Method2; override;
begin
writeln('Eat');
end;
procedure Method3; override;
begin
writeln('Think');
end;
end;
...
polymorph(new StudentInSession);
Места вызовов виртуальных методов в некотором коде могут быть заменены все одновременно с использованием следующего приема:
- Определим от базового класса, объект которого вызывает эти методы, потомка, в котором переопределим данные виртуальные методы.
- При конструировании вместо объекта базового класса создадим объект потомка и присвоим его указанной полиморфной переменной. При этом все вызовы виртуальных методов будут вызывать код для потомка.
Замечание. Код, содержащий вызовы виртуальных методов, всегда проектируется с учетом будущих изменений. При создании, в будущем, нового потомка этот код может вести себя совершенно по-другому, выполняя лишь основную роль. Поэтому мы всегда, когда пишем код с вызовами виртуальных методов, думаем о будущем.
Класс Base создавался только для того, чтобы его виртуальные методы были переопределены в потомке.
- Виртуальные методы, предназначенные для переопределения в потомке и ничего не выполняющие, называются абстрактными, а класс, их содержащий — абстрактным классом.
Объекты абстрактных классов создавать нельзя.
В соответствии с этим, сделаем наш базовый класс Base абстрактным:
type Base = class
public
procedure Method1; virtual; abstract;
procedure Method2; virtual; abstract;
procedure Method3; virtual; abstract;
end;
Класс Object — неявный предок всех классов .NET
Все классы в PascalABC.NET, если не указан другой предок, наследуются от класса Object.
Т.е. и integer, и string — классы.
<xh4> Интерфейс класса Object </xh4>
Object = class
function Equals(o: Object): boolean; virtual;
function ToString: string; virtual;
function GetType: System.Type;
Примечание. Как нам известно, использовать ключевые слова в качестве идентификаторов запрещено. Однако, можно использовать перед ними символ «&». Тогда можно, например, описать переменную &type.
Метод Equals
- Сравнивает текущий объект с объектом o и, если они равны, возвращает true, иначе — false.
- По умолчанию, все встроенные (а именно — размерные) типы и тип string сравниваются по значению, а все классы — по ссылке (две переменные считаются равными, если ссылаются на один объект).
Это можно изменить, переопределив метод Equals в потомке.
Метод ToString
- Возвращает строковое представление объекта.
Если не переопределен, то возвращает имя типа.
Метод GetType
- Возвращает объект типа System.Type, который характеризует тип данного объекта.
Пример 1.
var i: integer := 5;
begin
var s: string := i.ToString;
end.
<xh4> Переопределение методов Equals и ToString в классах Person и Student </xh4>
type Person = class
...
public
...
function Equals(o: object): boolean;
begin
if o = nil then
Result := false
else if GetType <> o.GetType then
Result := false
else
begin
var p := Person(o);
Result := (Name = p.Name) and (Age = p.Age);
end;
end;
function ToString: string;
begin
Result := Format(
'Имя: {0} Возраст: {1} ',
fName, fAge);
end;
type Student = class(Person)
...
public
...
function Equals(o: object): boolean;
begin
Result := inherited Equals(o);
if Result then
begin
var s := Student(o);
Result := (Course = s.Course) and (Group = s.Group);
end;
end;
function ToString: string;
begin
Result := inherited ToString + Format(
'Курс: {0} Группа: {1} ',
fCourse, fGroup);
end;
Полный текст новой версии классов Person и Student
Пример 2. Родословная переменной.
uses University;
procedure PrintLineage(o: object);
begin
var t := o.GetType;
writeln(t.Name);
repeat
t := t.BaseType;
if t = nil then
exit;
writeln(t.Name);
until false;
end;
begin
var s := new SeniorStudent('Иванов', 20, 4, 11, new Teacher('Петров'), Magister);
PrintLineage(s);
end.
Замечание. Полиморфизм обеспечивает изменчивость в будущем уже откомпилированного кода за счет создания подклассов.
Цепочка виртуальности и её разрыв
Пусть у нас есть следующая иерархия наследования:
A <— B <— C procedure Print; virtual; procedure Print; override; procedure Print; override;
- Говорят, что методы A.Print, B.Print и C.Print завязаны в цепочку виртуальности.
Унаследуем от класса C класс D следующим образом:
D (C) procedure Print;
Будет предупреждение: «Укажите override или reintroduce».
Ключевое слово reintroduce служит для разрыва цепочки виртуальности.
Если написать:
... reintroduce; virtual;
то это будет началом новой цепочки виртуальности.
Алгоритм поиска в цепочке виртуальности
Интерфейсы
Интерфейс - это специальным образом оформленный легковесный класс, задающий набор требований, которые должен реализовывать обычный класс.
В интерфейс входят заголовки методов и свойства с указанием доступа. Интерфейсы близки к абстрактным классам, но не могут содержать поля.
Все методы в интерфейсах считаются публичными, уровень доступа указывать не надо.
Пример.
interface IPrintable
procedure Print;
procedure Println;
end;
interface ICoords<T>
property X: T read;
property Y: T read;
end;
interface ICloneable // стандартный, из пространства имен System
procedure Clone;
end;
Интуитивно: интерфейсы - это роли, которые играют объекты классов в разных ситуациях.
Один и тот же класс может реализовывать несколько интерфейсов, один и тот же интерфейс может реализовываться совершенно различными классами.
Реализация интерфейсов
type Student = class(Person,ICloneable,IPrintable)
...
function Clone: Object;
begin
Result := new Student(Name,Age,Course,Group);
end;
procedure Print;
begin
...
end;
procedure Println;
begin
...
end;
end;
type List<T> = class(ICloneable,IPrintable)
...
end;
Класс наследуется от одного класса, но может реализовывать несколько интерфейсов.
Все методы и свойства интерфейса, реализуемые классом, должны быть объявлены публичными
Совершенно разнородные классы могут реализовывать одинаковые интерфейсы.
Совместимость по := и операции is as для интерфейсов
Для интерфейсов работают те же правила совместимости по присваиванию, что и для обычных классов:
- Если класс реализует интерфейс, то переменной типа интерфейс можно присвоить объект этого класса
- Можно использовать конструкции вида p is MyClass, p as MyClass, где p - переменная типа интерфейс
Интерфейсы и полиморфизм
Все методы интерфейсов, реализуемые классами, являются виртуальными - для этого необязательно использовать virtual
Если virtual не используется, то цепочка виртуальности прерывается, если используется - продолжается:
type IShape = interface(ICoords<integer>)
procedure Draw;
procedeure Hide;
procedeure MoveTo(x,y: integer);
procedeure MoveOn(dx,dy: integer);
end;
Shape = class(IShape)
...
procedure Draw; virtual;
procedeure Hide; virtual;
end;
Иерархия графических фигур - классический пример использования полиморфизма
Абстрактные методы и классы
Сделать Shape абстрактным
Полиморфные контейнеры
List<Shape> Цикл по полиморфному контейнеру
- с вызовом виртуального метода
- с вызовом индивидуального метода и использованием as
- с вызовом индивидуального метода и использованием GetType
Интерфейсы и наследование
Реализация интерфейсов является одной из форм наследования. В этой форме всегда выполняется принцип подстановки. Недостатки: все методы необходимо реализовывать с нуля Достоинства: нет "груза прошлого" - тяжеловесной реализации базовых классов, которая уже не нужна в производных. Пример с наследованием с ограничениями (круг от эллипса): реализация эллипса тяжеловесна, при реализации круга мы используем лишь часть этих возможностей.
Стандартные интерфейсы .NET
Пример 1. Интерфейс IComparable и его использование.
uses System;
type Student = class(Person,IComparable<Student>)
...
public
function CompareTo(o: Student): integer;
begin
var s := Student(o);
if (Course < s.Course) or (Course = s.Course) and (Group < s.Group) then
Result := -1
else if (Course = s.Course) and (Group = s.Group) then
Result := 0
else Result := 1;
end;
end;
Пример 2. Интерфейс IComparer и его использование.
Пример 3. Написание MinElem<T>(a: array of T); where T: IComparable<T>
Методы расширения
integer.Print
write(Self)
Методы расширения и интерфейсы
uses System.Collections.Generic;
function Identity(i: integer): integer;
begin
Result := i;
end;
procedure Print<T>(ie: IEnumerable<T>);
begin
foreach i: integer in ie do
write(i,' ');
writeln;
end;
begin
var a: array of integer := (1,5,3,10,7,4,8,3,11,2,2,3,4);
var a1: array of integer := (2,5,7,4,11,9,23,34);
writeln(a.All(Odd));
writeln(a.Any(Odd));
writeln(a.Average());
writeln(a.Contains(10));
writeln(a.Count());
writeln(a.Distinct().Count());
writeln(a.ElementAt(2));
writeln(a.ElementAtOrDefault(100));
Print(a.Concat(a1));
Print(a.Distinct());
Print(a.Except(a1));
Print(a.Intersect(a1));
Print(a.Union(a1));
Print(a.Skip(5));
Print(a.Take(5));
Print(a.TakeWhile(Odd));
Print(a.Where(Odd));
writeln(a.Where(Odd).Average());
writeln(a.Last());
writeln(a.Max());
writeln(a.Min());
var ff: System.Func<integer,integer> := f;
a.Select(Identity); // !!
writeln(a.SequenceEqual(a));
writeln(a.Sum());
a.OrderBy(Identity);
end.
Лямбды
uses Arrays;
var a: array of integer := (1,2,3,5,7);
begin
a := a.Select((x: integer)->x*x).ToArray();
a.Writeln;
end.
uses Core,Arrays;
var a: array of string := ('Hello','Abracadabra','Hi','Good','Bye');
begin
var res := a.OrderBy((x: string) -> x.Length);
res.ToArray().Writeln();
end.
writeln(a.First((x: integer) -> x>5));