Добавлен Msey,
опубликован
Раздел:
C#
В этой статье буду рассмотрены основные моменты при использовании интерфейсов.
Перед прочтением рекомендуется ознакомиться с наследованием классов и преобразованиями типов объекта.
Перед прочтением рекомендуется ознакомиться с наследованием классов и преобразованиями типов объекта.
Интерфейс - контракт ссылочного типа, позволяющий определить некоторый функционал для класса или структуры, при этом не имеющий конкретной реализации.
Для определения интерфейса используется ключевое слово interface, где, как правило, название начинается с заглавной буквы I. Пример IVehicle, IFigure, IEnumerable и так далее...
По умолчанию интерфейсы, как классы или структуры, по уровню доступа являются internal и не могут напрямую в сборке иметь модификаторы доступа с более низким уровнем, таким как protected, protected internal, private, private internal, однако вы можете их сделать public.
Также есть еще несколько важных (для .Net программистов с начальным уровнем опыта) подводных камней:
- члены интерфейса всегда публичные, так как основная задача интерфейса - обязать наследника класса или структуру получить весь его функционал, поэтому в интерфейсах вы не можете задать члену какой-либо модификатор доступа кроме как public
- изменить модификатор доступа самого интерфейса на более низкий уровень вы все же сможете, но только в том случае, если сам интерфейс находится в структуре или классе
Рассмотрим по порядку весь спектр вышеперечисленного:
Пример
namespace Msey
{
public interface IFruit
{
}
interface IBuilding
{
}
internal interface IVehicle // излишне, тк интерфейс уже по умолчанию {internаl}, как объяснялось выше
{
}
private interface ICannot // так нельзя
{
}
class ForPrivateInterfaces
{
private interface ICan // а вот так можно
{
}
}
struct ForPrivateInterfacesToo
{
private interface ICanToo // так тоже можно
{
}
}
}
Пример
Реализация интерфейса в классе выглядит следующим образом:
namespace Msey
{
interface IVehicle
{
void Move();
void Stop();
}
class Car : IVehicle
{
public void Move() // мы должны обязательно реализовать все методы наследуемого интерфейса, иначе будет ошибка компиляции
{
}
public void Stop()
{
}
}
}
Зачастую бывает необходимо наследовать несколько интерфейсов. C# поддерживает множественное наследование интерфейсов, чего, к сожалению (а на самом-то деле к счастью) нельзя сказать в силу наследования классов.
namespace Msey
{
interface IFirst
{
void FirstMove();
}
interface ISecond
{
void SecondMove();
}
class Car : IFirst, ISecond
{
public void FirstMove()
{
}
public void SecondMove()
{
}
}
}
Случай, когда интерфейсы нужно объединить:
public interface A
{
void ActionA();
}
public interface B
{
void ActionB();
}
public interface C
{
void ActionC();
}
interface ABC : A,B,C
{
}
class ImplementationABC : ABC
{
public void ActionA()
{
}
public void ActionB()
{
}
public void ActionC()
{
}
}
Кроме неявного применения интерфейсов рассмотренного выше, также еще существует и его явная реализация. При явной реализации указывается название метода или свойства вместе с названием интерфейса, при этом мы не можем применить какие-либо модификаторы доступа, так как, по умолчанию, члены явно реализованного интерфейса являются приватными и не могут быть доступными из экземпляра класса.
Пример
namespace Msey
{
interface IFirst
{
void FirstMove();
}
interface ISecond
{
void SecondMove();
}
class Car : IFirst, ISecond
{
public void IFirst.FirstMove() // так нельзя, методу задан модификатор доступа
{
}
void ISecond.SecondMove() // а вот так можно; модификаторов доступа нет
{
}
}
}
Иногда бывают такие случаи, когда несколько наследуемых интерфейсов имеют члены с одинаковыми названиями, тогда нам на помощь приходит преобразование типов объекта и явное применение интерфейса:
Пример
namespace Msey
{
interface IFirst
{
void Move();
}
interface ISecond
{
void Move();
}
class Car : IFirst, ISecond
{
void IFirst.Move()
{
}
void ISecond.Move()
{
}
public void BothInvoke()
{
((IFirst)this).Move();
((ISecond)this).Move();
}
}
}
Здесь разберем подробнее: при вызове BothInvoke(), через this берется ссылка на объект, в котором, собственно, и производится данный вызов. В нашем случае будет Car. Далее мы приводим тип объекта Car к интерфейсу IFirst и производим от его имени вызов метода Move().
Другими словами, от имени интерфейса IFirst мы в объекте Car вызываем метод Move().
Аналогично с интерфейсом ISecond.
((ISecond)this).Move();
Для чего нужны интерфейсы?
Это, пожалуй, самый частый вопрос который я слышал от начинающих программистов, и себя в том числе на начальных этапах программирования на C#. (ой, да ладно, я и до сих пор каждое утро себя спрашиваю).
- Интерфейс в практическом смысле дает возможность указать из чего именно должен состоять тот или иной объект разрабатываемой модели без описания поведения объекта.
- Интерфейс позволяет максимально ослабить зависимости между объектами.
- Интерфейс обеспечивает тестируемость за счет предыдущего пункта
Элементарный пример использования интерфейса
class Program
{
public interface IFigure
{
int NumberOfAngles { get; }
}
public class Triangle: IFigure
{
public int NumberOfAngles => 3;
}
public class Quad : IFigure
{
public int NumberOfAngles => 4;
}
public class Circle : IFigure
{
public int NumberOfAngles => 0;
}
static void Main(string[] args)
{
List<IFigure> AllFigures = new List<IFigure>();
Triangle triangle = new Triangle();
Quad quad = new Quad();
Circle circle = new Circle();
AllFigures.Add(triangle);
AllFigures.Add(quad);
AllFigures.Add(circle);
foreach (var figure in AllFigures)
Console.WriteLine("Figure " + figure.GetType().Name + " has "+figure.NumberOfAngles + " angles.");
}
}
Вывод программы будет следующим:
Figure Triangle has 3 angles.
Figure Quad has 4 angles.
Figure Circle has 0 angles. // да-да, без обработчика отсутствия углов для краткости
Есть интерфейс, который является родителем трех классов-фигур. Их объединяет целочисленное значение, несущее информацию о количестве углов в фигуре. Как нам добавить все фигуры в список и вывести только необходимую информацию? Все верно. На помощь приходит интерфейс, который строго описывает поведение каждой фигуры, при этом не позволяя выходить за рамки дозволенного.
Буду чрезвычайно признателен правкам и дополнениям.
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Отредактирован nvc123
но тут судя по вопросу человек не понимает не в чём отличие абстрактного класса от интерфейса а применение полиморфизма
*конкурс