Upload
cs-center
View
303
Download
2
Embed Size (px)
Citation preview
План лекции
• Классы и интерфейсы• Наследование• Пример реализации
стандартных интерфейсов• Принцип подстановки
Лисков(LSP)
02.05.2023 Толстиков Никита 2План лекции
Классы
• Ссылочный тип данных• Может содержать поля,
методы, свойства, события• Позволяет обеспечить
инкапсуляцию с помощью модификаторов доступа
02.05.2023 Толстиков Никита 3Классы
public class Rectangle{}
Классы
02.05.2023 Толстиков Никита 4Классы
public class Rectangle{ private int myHeight; private int myWidth;
public Rectangle(int width, int height) { /* ... */ }
public int CalculateArea() { /* ... */ }
public int Height { get { /* ... */ } set { /* ... */ } } public int Width { get { /* ... */ } set { /* ... */ } }}
Наследование
02.05.2023 Толстиков Никита 5Наследование
• Можно обращаться к членам базового класса через производный класс
class Ogr : Monster{
public string Color { get; } public void Jump() { }}
Наследование конструкторов
02.05.2023 Толстиков Никита 6Наследование
• Для вызова базового конструктора используется ключевое слово base
public Ogr(string color) : base(100){
Color = color;}public Ogr()
: this(“White") { }
...Ogr ogr = new Ogr("Green");
public Ogr(string color) // ошибка { Color = color; }
Переопределение поведения
02.05.2023 Толстиков Никита 7Наследование
• Ключевые слова virtual и override позволяют переопределить поведение базового класса:class Monster
{...
public virtual void Kill(Monster m) { m.Die(); }}
class Ogr : Monster{ public override void Kill(Monster other) { Console.WriteLine("Aaargh!"); base.Kill(other); }}
Переопределение поведения
02.05.2023 Толстиков Никита 8Наследование
• Если забыть про override:
• То огр заговорит, если указатель на него типа Ogr:
class Ogr : Monster{
public void Kill(Monster m) {...}...
}
Monster ogr1 = new Ogr("green");Ogr ogr2 = new Ogr("red");
ogr1.Kill(ogr1);ogr2.Kill(ogr2);
Переопределение поведения
02.05.2023 Толстиков Никита 9Наследование
• Warning:
• Если вы и правда хотели скрыть метод то воспользуйтесь ключевым словом new
Warning 1'HelloWorld.Ogr.Kill(HelloWorld.Monster)' hides inherited member 'HelloWorld.Monster.Kill(HelloWorld.Monster)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
Абстрактный класс
02.05.2023 Толстиков Никита 10Наследование
• Нельзя создать объект абстрактного класса
• Можно реализовать часть методов• Может иметь конструкторы
internal abstract class Monster{
... public virtual void Kill(Monster m) { m.Die();
}public abstract int Height { get; }
public abstract void Die();}
Абстрактный класс
02.05.2023 Толстиков Никита 11Наследование
• Для наследования от абстрактного класса нужно переопределить все методы помеченные как abstract
class Ogr : Monster{
public override int Height { get { return 100; } } public override void Die() { Health = 0; }}
Sealed классы
02.05.2023 Толстиков Никита 12Наследование
• Ключевое слово sealed запрещает наследование
• Все value-типы sealed. Т.е. нельзя наследоваться от struct и примитивных типов (int, string, double и т.д.)
sealed class BestClass{}
Интерфейсы
02.05.2023 Толстиков Никита 13Интерфейсы
• Интерфейс – контракт на реализацию действия
• Может содержать: свойства, методы, индексаторы и события
interface IMonster{
int Id { get; }string Name { get; }int Health { get; set; }
void Die();void Kill(IMonster monster);
string this[int index] { get; }}
Интерфейсы
02.05.2023 Толстиков Никита 14Интерфейсы
• Реализация интерфейса:class Monster : IMonster{
public int Id { get; }public string Name { get; set; }public int Health { get; set; }
public void Die(){
Health = 0;}public void Kill(IMonster m){
m.Die();}
private readonly string[] myKnownWords = {"Argh", "Life for Aiure"};public string this[int i]{
get { return myKnownWords[i]; }}
}
Интерфейсы
02.05.2023 Толстиков Никита 15Интерфейсы
• Объект интерфейса нельзя создать
• Интерфейс может быть типом параметра
• Приведение к интерфейсу неявное:IMonster m1 = new Monster();Monster m2 = new Monster();
bool b = m2 is IMonster; //true m1 = m2;m1.Kill(m2);
Реализация интерфейсов
02.05.2023 Толстиков Никита 16Интерфейсы
• IDisposable – интерфейс для безопасной работы с ресурсами. Применяется в конструкции using
• IComparable – задает порядок сортировки объектов типа
interface IComparable{ int CompareTo(object obj);}
Реализация интерфейсов
02.05.2023 Толстиков Никита 17Интерфейсы
• IComparable состоит из метода CompareTo который возвращает число:–Меньше ноля, если порядок this < obj– Ноль, если порядок this равен obj– Больше ноля, если порядок this > obj
• Большинство классов и структур FCL реализуют этот интерфейс
• Переиспользуйте стандартные реализации
Реализация интерфейсов
02.05.2023 Толстиков Никита 18Интерфейсы
class BigNumber : IComparable{ ... public int CompareTo(object obj) { if (obj == null) return 0;
if (!(obj is BigNumber)) throw new ArgumentException("Object is not BigNumber");
BigNumber other = (BigNumber) obj; return this.myValue.CompareTo(other.myValue); }}
Реализация интерфейсов
02.05.2023 Толстиков Никита 19Интерфейсы
• Интерфейс IClonable имеет единственный метод Clone()
public class CloneableOgr : Ogr, ICloneable { public CloneableOgr(string color) : base(color) { }
public object Clone() { CloneableOgr result = new CloneableOgr(Color); return result; } }
Реализация интерфейсов
02.05.2023 Толстиков Никита 20Интерфейсы
О IEnumerable, ICollection, IQueryable, ISerializable и т.д. будет рассказано на следующих лекциях
НЕ ПРОПУСТИТЕ!!!
Интерфейсы
02.05.2023 Толстиков Никита 21Интерфейсы
• Явная(explicit) реализация интерфейса:interface ILeft
{void Move();
}
interface IRight{
void Move();}
class MoveableOject : ILeft, IRight{
void ILeft.Move() { }void IRight.Move() { }
}
Интерфейсы
02.05.2023 Толстиков Никита 22Интерфейсы
• При явной реализации вызвать метод можно только от типа интерфейса:
• При помощи явной реализации можно улучшить инкапсуляцию, скрыв методы от пользователя и показав их только при использовании интерфейса
MoveableOject obj = new MoveableOject();
((ILeft)obj).Move();((IRight)obj).Move();
LSP
02.05.2023 Толстиков Никита 23LSP
• LSP(Liskov substitution principle) – функции, использующие базовый тип должны корректно работать на производных типах
• Т.е. подкласс не должен менять поведение неожиданно для пользователя
Пример
02.05.2023 Толстиков Никита 24LSP
class Rectangle { public Rectangle(int width, int height) { Width = width; Height = height; } public int Height { get; set; } public int Width { get; set; } public int Area { get { return Height * Width; } } }
Пример
02.05.2023 Толстиков Никита 25LSP
class Square : Rectangle { public override int Width { get { return base.Width; } set { base.Width = value; base.Height = value; } } public override int Height { get { return base.Height; } set { base.Height = value; base.Width = value; } } }
Пример
02.05.2023 Толстиков Никита 26LSP
Rectangle rectangle = new Square();rectangle.Width = 10;rectangle.Height = 5;Console.WriteLine(rectangle.Area); //Результат: 25
• Тем самым пользователь не поймет почему результат 25, а не 50
• Следствие: наследование не должно применяться для переиспользования кода, если это нарушает LSP
The End
02.05.2023 Толстиков Никита 27Собственные типы