Язык С#. Интерфейсы. Лекция #3

Содержание

Слайд 2

Определение интерфейса

Интерфейс – это набор семантически связанных абстрактных методов, свойств и событий.
Класс,

Определение интерфейса Интерфейс – это набор семантически связанных абстрактных методов, свойств и
реализующий интерфейс, должен самостоятельно полностью переопределить все члены данного интерфейса.

Слайд 3

Пример интерфейса

// Этот интерфейс определяет возможности
// работы с углами геометрической фигуры
public interface

Пример интерфейса // Этот интерфейс определяет возможности // работы с углами геометрической
IPointy
{
// Автоматически этот член интерфейса становится абстрактным
byte GetNumberOfPoints();
// Чтобы сделать это свойство «только для чтения»
// достаточно просто удалить блок set
// byte Points(get; set;)
}

Слайд 4

Пример интерфейса

// Любой класс может реализовывать любое количество интерфейсов, но он должен

Пример интерфейса // Любой класс может реализовывать любое количество интерфейсов, но он

// производиться только от одного базового класса:
public class Hexagon : Shape, IPointy
{
public Hexagon(){}
public Hexagon(string name): base(name){}
public override void Draw()
{
// Вспомним, что в классе Shape определено свойство PetName
Console.WriteLine("Drawing {0} the Hexagon", PetName);
}
// Реализация IPointy
public byte GetNumberOfPoints()
{
return 6;
}
}

Слайд 5

Пример интерфейса

public class Triangle : Shape, IPointy
{
public Triangle(){}
public Triangle(string name) : base(name)

Пример интерфейса public class Triangle : Shape, IPointy { public Triangle(){} public
{}
public override void Draw()
{
Console.WriteLine("Drawing {0} the Triangle", PetName);
}
// Реализация IPointy
public byte GetNumberOfPoints()
{
return 3;
}
}

В классе должны быть реализованы все методы интерфейса, половинчатого решения быть не может

Слайд 6

Получение ссылки на интерфейс

// Получаем ссылку на интерфейс IPointy,
// используя явное

Получение ссылки на интерфейс // Получаем ссылку на интерфейс IPointy, // используя
приведение типов
Hexagon hex = new Hexgon("Bill");
IPointy itfPt = (IPointy) hex;
Console.WriteLine (itfPt.GetNumberOfPoints());

// Перехват исключения
Circle c = new Circle("Lisa");
IPointy itfPt;
try { itfPt = (IPointy) c;
Console.WriteLine (itfPt.GetNumberOfPoints());
}
catch (IvalidCastException e)
{ Console.WriteLine("Oops! Not pointy…");
}

Слайд 7

Получение ссылки на интерфейс с помощью оператора as

// Еще один способ получить

Получение ссылки на интерфейс с помощью оператора as // Еще один способ
ссылку на интерфейс
Hexagon hex = new Hexgon("Bill");
IPointy itfPt;
itfPt = hex as IPointy;
Console.WriteLine (itfPt.GetNumberOfPoints());
if (itfPt != null)
Console.WriteLine(itfPt.GetNumberOfPoints());
else
Console.WriteLine("Oops! Not pointy…");

Слайд 8

Проверка существования интерфейса с помощью оператора is

// Есть ли у этой фигуры

Проверка существования интерфейса с помощью оператора is // Есть ли у этой
углы?
Triangle t = new Triangle();
if (t is IPointy)
Console.WriteLine(t.GetNumberOfPoints());
else
Console.WriteLine("Oops! Not pointy…");

Слайд 9

Пример использования is

// Давайте выясним (во время выполнения), у каких
// геометрических фигур

Пример использования is // Давайте выясним (во время выполнения), у каких //
есть углы
Shape[] s = {new Hexagon(), new Circle(),
new Triangle("Joe"), new Circle("JoJO")}
for(int i = 0; i < s.length; i++)
{
// Вспомним, что базовый класс Shape() определяет
// абстрактный метод Draw()
s[i].Draw();
// У каких геометрических фигур в массиве есть углы?
if (s[i] is IPointy)
Console.WriteLine("Points: {0}",
((IPointy)s[i]).GetNumberOfPoints());
else
Console.WriteLine(s[i].PetName +
"\'s not pointy!");
}

Слайд 10

Интерфейсы как параметры

// Интерфейс для отображения фигур в трех измерениях
public interface IDraw3D

Интерфейсы как параметры // Интерфейс для отображения фигур в трех измерениях public
{ void Draw3D(); }
// Circle поддерживает интерфейс IDraw3D
public class Circle : Shape, IDraw3D
{ ...
public void Draw3D()
{
Console.WriteLine("Drawing Circle in 3D!");
}
}
// Если наши типы поддерживают несколько интерфейсов, нужно
// просто перечислить эти интерфейсы через запятую, как обычно:
public class Hexagon : Shape, IPointy, IDraw3D
{ ...
public void Draw3D()
{
Console.WriteLine("Drawing Hexagon in 3D!");
}
}

Слайд 11

Интерфейсы как параметры

// Создаем несколько геометрических фигур. Если они поддерживают
// отображение в

Интерфейсы как параметры // Создаем несколько геометрических фигур. Если они поддерживают //
трех измерениях, делаем это!
public class ShapesApp
{
// Будут нарисованы все объекты, поддерживающие интерфейс IDraw3D
public static void DrawThisShapeIn3D(IDraw3D itf3d)
{
itf3d.Draw3D();
}
public static int Main(string[] args)
{
Shape[] s = {new Hexagon(), new Circle(), new Triangle(), new Circle("JoJo")};
for(int i=0; i {
// Могу ли я нарисовать этот объект в трех измерениях?
if(s[i] is IDraw3D)
DrawThisShapeIn3D((IDraw3D)s[i]);
}
return 0;
}
}

Слайд 12

Разрешение конфликтов имен

public interface IDraw3D
{ void Draw3D();
}
// А что будет,

Разрешение конфликтов имен public interface IDraw3D { void Draw3D(); } // А
если мы сделаем
public interface IDraw3D
{
void Draw();
}
public class Line : Shape, IDraw3D
// И базовый класс и интерфейс определяют метод Draw
{
public override void Draw()
{
Console.WriteLine("Drawing a line…");
}
}

Слайд 13

Разрешение конфликтов имен

// Вызываем Line.Draw()
Line myLine = new Line();
myLine.Draw()
// Вызываем Line.Draw() еще

Разрешение конфликтов имен // Вызываем Line.Draw() Line myLine = new Line(); myLine.Draw()
раз, но уже по-другому
IDraw3D itfDraw3D = (IDraw3D) myLine;
itfDraw3D.Draw();
// В обоих случаях будет вызван один и тот же метод!

Слайд 14

Явная реализация интерфейса

// При помощи явной реализации методов интерфейса мы можем
// определить

Явная реализация интерфейса // При помощи явной реализации методов интерфейса мы можем
разные варианты метода Draw()
public class Line : Shape, IDraw3D
{
// Этот метод можно будет вызвать только через
// ссылку на интерфейс IDraw3D
void IDraw3D.Draw()
{
Console.WriteLine("Drawing a 3D line...");
}
// Этот метод можно будет вызвать только через
// ссылку на объект класса Line
public override void Draw()
{
Console.WriteLine("Drawing a line...");
}
}

Нельзя использовать модификаторы области видимости для методов интерфейса

Слайд 15

Явная реализация интерфейса

// Конфликтов имен не будет!
public class SuperImage : IDraw, IDrawToPrinter,

Явная реализация интерфейса // Конфликтов имен не будет! public class SuperImage :
IDraw3D
{
void IDraw.Draw()
{
// Вывод обычного плоского изображения
}
void IDrawToPrinter.Draw()
{
// Вывод на принтер
}
void IDraw3D.Draw()
{
// Поддержка объемного изображения
}
}

Слайд 16

Создание иерархий интерфейсов

// Базовый интерфейс
interface IDraw
{
void Draw();
}
interface IDraw2 : IDraw
{
void

Создание иерархий интерфейсов // Базовый интерфейс interface IDraw { void Draw(); }
IDrawToPrinter();
}
interface IDraw3 : IDraw2
{
void IDrawToMetafile();
}

Слайд 17

Создание иерархий интерфейсов

// Этот класс будет поддерживать IDraw, IDraw2 и IDraw3
public class

Создание иерархий интерфейсов // Этот класс будет поддерживать IDraw, IDraw2 и IDraw3
SuperImage : IDraw3
{
// Используем явную реализацию интерфейсов, чтобы привязать
// методы к конкретным интерфейсам
void IDraw.Draw()
{
// Обычный вывод на экран
}
void IDraw2.DrawToPrinter()
{
// Вывод на принтер
}
void IDraw3.DrawToMetafile()
{
// Вывод в метафайл
}
}

Слайд 18

Создание иерархий интерфейсов

// Проверяем наши интерфейсы
public class TheApp
{
public static int Main(string[]

Создание иерархий интерфейсов // Проверяем наши интерфейсы public class TheApp { public
args)
{
SuperImage si = new SuperImage();
// Получаем ссылку на интерфейс IDraw
IDraw itfDraw = (IDraw)si;
itfDraw.Draw();
// А теперь получаем ссылку на интерфейс IDraw3
if(itfDraw is IDraw3)
{
IDraw3 itfDraw3 = (IDraw3)itfDraw;
itfDraw3.DrawToMetaFile();
itfDraw3.DrawToPrinter();
}
return 0;
}
}

Слайд 19

Наследование от нескольких базовых интерфейсов

interface IBasicCar
{ void Drive();
}
interface IUnderwaterCar
{ void Dive();
}
interface IJamesBondCar : IBasicCar,

Наследование от нескольких базовых интерфейсов interface IBasicCar { void Drive(); } interface
IUnderwaterCar
{ void TurboBoost();
}
public class JBCar : IJamesBondCar
{ public JBCar(){}
// Унаследованные члены
void IBasicCar.Drive() {Console.WriteLine("Speeding up...");}
void IUnderwaterCar.Dive() {Console.WriteLine("Submerging...");}
void IJamesBondCar.TurboBoost() {Console.WriteLine("Blast off!");}
}

Слайд 20

Наследование от нескольких базовых интерфейсов

JBCar j = new JBCar();
if(j is IJamesBondCar)
{
((IJamesBondCar)j).Drive();
((IJamesBondCar)j).TurboBoost();
((IJamesBondCar)j).Dive();
}

Наследование от нескольких базовых интерфейсов JBCar j = new JBCar(); if(j is

Слайд 21

Использование встроенных интерфейсов

Интрефесы IEnumerate, IEnumerate

Использование встроенных интерфейсов Интрефесы IEnumerate, IEnumerate

Слайд 22

Описание класса Car

// Cars — набор объектов класса Car
public class Cars
{
private Car[] carArray;
//

Описание класса Car // Cars — набор объектов класса Car public class
При создании объекта класса Cars заполняем его несколькими
// объектами Car
public Cars()
{
carArray = new Car[4];
carArray[0] = new Car("FeeFee", 200, 0);
carArray[1] = new Car("Clunker", 90, 0);
carArray[2] = new Car("Zippy", 30, 0);
carArray[3] = new Car("Fred", 30, 0);
}
}

Слайд 23

Применить foreach?

// Кажется очень заманчивым
public class CarDriver
{
public static void Main()
{

Применить foreach? // Кажется очень заманчивым public class CarDriver { public static
Cars carLot = new Cars();
// Пробуем использовать foreach для обращения
// к каждому объекту Car внутри набора,
// представленного carLot
foreach (Car c in carLot)
{
Console.WriteLine("Name: {0}", c.PetName);
Console.WriteLine("Max speed: {0}", c.MaxSpeed);
}
}
}

Класс Cars не реализует метод GetEnumerator();
Определяется в IEnumerable в System.Collection

Слайд 24

Interface IEnumerable

// Необходимо, чтобы класс реализовывал
// интерфейс IEnumerable
public class Cars

Interface IEnumerable // Необходимо, чтобы класс реализовывал // интерфейс IEnumerable public class
: IEnumerable
{

// Интерфейс IEnumerable определяет этот метод
// и ничего больше!
public IEnumerator GetEnumerator()
{
// А дальше-то что?
}

}

Слайд 25

Интерфейс IEnumerator

public interface IEnumerator
{
// Передвинуть внутренний указатель на одну позицию
bool

Интерфейс IEnumerator public interface IEnumerator { // Передвинуть внутренний указатель на одну
MoveNext();
// Получить текущий элемент набора
object Current (get;)
// Установить внутренний указатель на начало набора
void Reset();
}

Слайд 26

Модификация класса Cars

// Набор объектов Car с реализованным нумератором!
public class Cars: IEnumerator,

Модификация класса Cars // Набор объектов Car с реализованным нумератором! public class
IEnumerable
{
private car[ ] carArray;
int pos = -1; // Переменная для текущей позиции элемента в массиве
public Cars()
{ // Здесь мы создаем несколько объектов класса Car и добавляем их в массив
}
public bool MoveNext() // Реализация методов интерфейса IEnumerator
{
if (pos < carArray.Length) { pos++; return true; }
else return false;
}
public void Reset() { pos = 0; }
public object Current
{ get { return carArray[pos]; }
}
// Реализация метода интерфейса IEnumerable
public IEnumerator GetEnumerator()
{ return (IEnumerator) this;
}
}

Слайд 27

Применить foreach!

public class CarDriver
{
public static void Main()
{
Cars carLot =

Применить foreach! public class CarDriver { public static void Main() { Cars
new Cars();
// Теперь можно использовать foreach для обращения
// к каждому объекту Car внутри набора
foreach (Car c in carLot)
{
Console.WriteLine("Name: {0}", c.PetName);
Console.WriteLine("Max speed: {0}", c.MaxSpeed);
}
}
}

Слайд 28

Дополнительные способы обращения к объектам Car

// Обращаемся к объектам Car через IEnumerator
IEnumerator

Дополнительные способы обращения к объектам Car // Обращаемся к объектам Car через
itfEnum;
itfEnum = (IEnumerator)carLot;
// Устанавливаем курсор на начало
itfEnum.Reset();
// Перемещаем курсор вперед на один шаг
itfEnum.MoveNext();
// Выбираем одну машину и включаем в ней радио
object curCar = itfEnum.Current;
((Car)curCar).CrankTunes(true);

Слайд 29

Создание клонируемых объектов

Интерфейс ICloneable

Создание клонируемых объектов Интерфейс ICloneable

Слайд 30

Поверхностное копирование (shallow copy)

// Наш класс — это просто точка с координатами на

Поверхностное копирование (shallow copy) // Наш класс — это просто точка с
плоскости
public class Point
{
// Поля (открытые переменные)
public int x, y;
// Конструкторы
public Point() {}
public Point(int x, int y){this.x = x; this.y = y;}
// Замещаем Object.ToString()
public override string ToString()
{return "X: " + x + " Y: " + y; }
}

Оператор = вызывает метод MemberwiseClone();

Слайд 31

Глубокое копирование (deep copy)

// Реализуем в классе Point поддержку глубокого копирования
//

Глубокое копирование (deep copy) // Реализуем в классе Point поддержку глубокого копирования
через интерфейс ICloneable
public class Point : ICloneable
{
// Данные о состоянии объекта
public int x, y;
// Конструкторы
public Point() {}
public Point(int x, int y){this.x = x; this.y = y;}
// Реализуем единственный метод ICloneable
public object Clone()
{
return new Point(this.x, this.y)
}
public override string ToString()
{return "X: " + x + " Y: " + y; }
}

Слайд 32

Глубокое копирование (deep copy)

// Обратите внимание, что Clone() возвращает
// "объект вообще".

Глубокое копирование (deep copy) // Обратите внимание, что Clone() возвращает // "объект
Чтобы получить из него
// нужный нам производный тип, придется провести
// явное преобразование типов
Point p3 = new Point(100, 100);
Point p4 = (Point) p3.Clone();
// Меняем p4.x (при этом p3.x не изменится)
p4.x = 0;
// Проверяем, так ли это:
Console.WriteLine("Deep copying using Clone()");
Console.WriteLine(p3);
Console.WriteLine(p4)

Слайд 33

Сравнивание объектов

Интерфейс IComparable

Сравнивание объектов Интерфейс IComparable

Слайд 34

Интерфейс IComparable

Car[] myAutos = new Car[5];
myAutos[0] = new Car(123, "Rusty");
myAutos[1] = new

Интерфейс IComparable Car[] myAutos = new Car[5]; myAutos[0] = new Car(123, "Rusty");
Car(6, "Mary");
myAutos[2] = new Car(83, "Viper");
myAutos[3] = new Car(13, "NoName");
myAutos[4] = new Car(9873, "Chucky");
Array.Sort(myAutos); // Что-то не выходит

// Этот интерфейс позволяет определить место объекта
// среди других аналогичных объектов
interface IComparable
{
int CompareTo(object o)
}

Слайд 35

Реализация интерфейса IComparable

// Такая реализация метода CompareTo() позволит сортировать
// объекты автомобилей по

Реализация интерфейса IComparable // Такая реализация метода CompareTo() позволит сортировать // объекты
значению идентификатора — CarID
public class Car : IComparable
{
...
// Реализация IComparable
int IComparable.CompareTo(object o)
{
Car temp = Car(o);
if(this.CarID > temp.CarID)
return 1;
if(this.CarID < temp.CarID)
return -1;
else
return 0;
}
}

Слайд 36

Применяем интерфейс IComparable

// Применяем реализованный нами интерфейс IComparable на практике
public class

Применяем интерфейс IComparable // Применяем реализованный нами интерфейс IComparable на практике public
CarApp
{
public static int Main(string[] args)
{
// Создаем массив объектов Car
Car[] myAutos = new Car[5];
myAutos[0] = new Car(123, "Rusty");
myAutos[1] = new Car(6, "Mary");
myAutos[2] = new Car(83, "Viper");
myAutos[3] = new Car(13, "NoName");
myAutos[4] = new Car(9873, "Chucky");
// Выводим информацию об автомобилях из неупорядоченного массива на системную консоль
Console.WriteLine("Here is the unordered set of cars:");
foreach(Car c in MyAutos)
Console.WriteLine(c.ID + " " + c.PetName);
// А теперь используем возможности только что реализованного IComparable
Array.Sort(myAutos);
// Выводим информацию уже из упорядоченного массива
Console.WriteLine("Here is the ordered set of cars:");
foreach(Car c in myAutos)
Console.WriteLine(c.ID + " " c.PetName);
return 0;
}
}

Слайд 37

Сортировка по нескольким идентификаторам Интерфейс IComparer в System.Collection

// Стандартный способ сравнения двух объектов
interface

Сортировка по нескольким идентификаторам Интерфейс IComparer в System.Collection // Стандартный способ сравнения
IComparer
{
int Compare(object o1, object o2)
}

Слайд 38

Создание вспомогательного класса

// Этот вспомогательный класс нужен для
// сортировки объектов Car

Создание вспомогательного класса // Этот вспомогательный класс нужен для // сортировки объектов
по PetName
using System.Collections;
public class SortByPetName : IComparer
{
public SortByPetName(){}
// Сравниваем прозвища (PetName) объектов
int IComparer.Compare(object o1, object o2)
{
Car t1 = (Car)o1;
Car t2 = (Car)o2;
return String.Compare(t1.PetName, t2.PetName);
}
}

Слайд 39

Сортировка по указанному полю

// Now sort by pet name.
Array.Sort(myAutos, new SortByPetName());
Console.WriteLine("\nOrdering by

Сортировка по указанному полю // Now sort by pet name. Array.Sort(myAutos, new
pet name:");
foreach(Car c in myAutos)
Console.WriteLine(c.ID + " " + c.PetName);

Слайд 40

Можно включить статическое свойство

public class Car : IComparable
{
// As a nested class!
private

Можно включить статическое свойство public class Car : IComparable { // As
class SortByPetNameHelper : IComparer
{ public SortByPetNameHelper(){}
// IComparer impl.
int IComparer.Compare(object o1, object o2)
{ Car t1 = (Car)o1;
Car t2 = (Car)o2;
return String.Compare(t1.PetName, t2.PetName);
}
}
// Property to return the SortByPetName comparer.
public static IComparer SortByPetName
{ get { return (IComparer)new SortByPetNameHelper(); } }
// Теперь можно так
Array.Sort(myAutos, Car.SortByPetName);

Слайд 41

Пространство имен System.Collections

Интерфейсы и классы

Пространство имен System.Collections Интерфейсы и классы

Слайд 42

Интерфейсы

Интерфейсы

Слайд 43

Классы

Классы

Слайд 44

Применение ArrayList

// Нам больше не нужно реализовывать IEnumerator — все уже сделано за

Применение ArrayList // Нам больше не нужно реализовывать IEnumerator — все уже
нас в ArrayList
public class Cars : IEnumerable
{
// Это — тот самый внутренний класс, который и будет делать всю работу
private ArrayList carList;
// Создаем объект класса carList при помощи конструктора Cars
public Cars() {carList = new ArrayList();}
// Реализуем нужные нам методы для приема вызовов извне и передачи их carList
// Метод для вставки объекта Car
public void AddCar(Car c) { carList.Add(c); }
// Метод для удаления объекта Car
public void RemoveCar(int carToRemove) { carList.RemoveAt(carToRemove); }
// Свойство, возвращающее количество объектов Car
public int CarCount { get { return carList.Count; } }
// Метод для очистки объекта — удаления всех объектов Car
public void ClearAllCars() { carList.Clear(); }
// Метод, который отвечает на вопрос — есть ли уже в наборе такой объект Car
public bool CarIsPresent(Car c) { return carList.Contains(c); }
// А все, что связано с реализацией IEnumerator, мы просто перенаправляем в carList
public IEnumerator GetEnumerator() { return carList.GetEnumerator(); }
}