- •Функции
- •Определение и использование функций Определение и использование базовой функции базовой функции
- •Перегрузка функций
- •Делегаты
- •Применение делегата для вызова функции
- •Классы Определение классов в с#
- •Определение членов
- •Конструкторы и деструкторы
- •Последовательность выполнения конструкторов
- •Интерфейсы
- •Реализация интерфейсов
- •Реализация интерфейсов в классах
- •Наследование
- •Полиморфизм
- •Полиморфизм интерфейсов
Реализация интерфейсов
Интерфейсы определяются подобно классам с использованием примерно такого кода:
interface ImyInterface
{
// Члены интерфейса.
}
Члены интерфейсов тоже определяются подобно членам классов, но имеют несколько следующих важных отличий.
При определении членов интерфейсов не разрешается использовать модификаторы доступа (ни public, ни private, ни protected, ни internai); все члены интерфейсов неявно являются общедоступными.
Члены интерфейсов не могут содержать тело кода.
В интерфейсах не могут определяться члены типа полей.
Члены интерфейсов не могут определяться с использованием таких ключевых слов, как static, virtual, abstract или sealed.
В члены интерфейсов запрещено добавлять определения типов.
Члены интерфейсов, однако, можно определять с использованием ключевого слова new при желании скрыть тех членов, которые наследуются от базовых интерфейсов:
interface IMyBaseInterfасе
{
void DoSomething();
}
interface IMyDerivedInterfасе : IMyBaseInterfасе
{
new void DoSomething ( );
}
Делается это тем же самым образом, как и сокрытие унаследованных членов класса.
В тех свойствах, которые определяются в интерфейсах, может определяться как один, так и оба блока get и set в зависимости от того, какой уровень доступа обеспечивается к свойству:
interface IMylnterfасе
{
int Mylnt
{
get;
set;
}
}
Здесь y int-свойства MyInt имеется оба блока — и get, и set. В случае свойства с более ограниченным доступом какой-то из них может быть опущен.
Данный синтаксис напоминает синтаксис автоматических свойств, но важно не забывать о том, что автоматические свойства определяются только для классов, а не для интерфейсов, и что в их случае обязательным является наличие обоих блоков get и set.
В интерфейсах не указывается, как должны храниться данные свойств. В них, например, нельзя указывать те поля, которые могут использоваться для хранения данных свойств. И, наконец, последнее: интерфейсы, подобно классам, могут определяться в виде членов классов (но не в виде членов других экземпляров, поскольку интерфейсы не могут содержать определений типов).
Реализация интерфейсов в классах
В классе, который реализует интерфейс, должны обязательно содержаться реализации для всех членов этого интерфейсов, которые, в свою очередь, должны обязательно соответствовать указанным сигнатурам (а также указанным блокам get и set) и являться общедоступными (public):
public interface IMylnterfасе
{
void DoSomething();
void DoSomethingElse();
}
public class MyClass : IMylnterface
{
public void DoSomething()
{
}
public void DoSomethingElse ( )
{
}
}
Члены интерфейсов допускается реализовать с использованием ключевого слова virtual или abstract, но не ключевого слова static или constant.
public class MyBaseClass
{
public void DoSomething ( )
{
}
}
public class MyDerivedClass : MyBaseClass, IMylnterface
{
public void DoSomethingElse ( )
{
}
}
Наследование от базового класса, реализующего данный интерфейс, означает, что данный интерфейс также неявно поддерживается и производным классом.
Например:
public interface IMylnterface
{
void DoSomething ();
void DoSomethingElse ();
}
public class MyBaseClass : IMylnterface
{
public virtual void DoSomething ( )
{
}
public virtual void DoSomethingElse ( )
{
}
}
public class MyDerivedClass : MyBaseClass
{
public override void DoSomething ( )
{
}
}
Очевидно, что реализации в базовых классах лучше определять как виртуальные, чтобы в производных классах их можно было заменять, а не скрывать. Если бы пришлось скрывать член базового класса с использованием ключевого слова new, а не переопределять его, как было показано здесь, тогда метод IMyInterfасе. DoSomething всегда бы ссылался на ту версию, которая содержится в базовом классе, даже если бы доступ к производному классу осуществлялся через интерфейс.
Явная реализация членов интерфейса
Члены интерфейсов могут также реализоваться и явно самим классом. В случае применения такого подхода доступ к члену может осуществляться только через интерфейс, но не класс. Что касается членов, реализуемых неявно, которые демонстрировались в предыдущем разделе, то к ним доступ может осуществляться и тем, и другим способом.
Например, если бы класс MyClass реализовал метод DoSomething интерфейса IMyInterface неявно, как это и было в предыдущем примере, тогда следующий код был бы допустимым:
MyClass myObj = new MyClass ();
myObj.DoSomething();
Такой код тоже был бы допустимым:
MyClass myObj = new MyClass ();
IMylnterface mylnt = myObj;
mylnt.DoSomething( ) ;
Если же MyDerivedClass реализовал бы DoSomething явно, тогда использовать бы можно было только второй прием. Необходимый для этого код выглядит следующим образом:
public class MyClass : IMylnterface
{
void IMylnterface.DoSomething ( )
{
}
public void DoSomethingElse ( )
{
}
}
Здесь метод DoSomething реализуется явно, а метод DoSomethingElse — неявно. Получать доступ непосредственно через экземпляр объекта myClass можно только к последнему.
При реализации интерфейса со свойством нужно обязательно реализовать соответствующие блоки get и set. Это не совсем так: в свойство внутри класса, где определяющий это свойство интерфейс содержит только блок set, допускается добавлять блок get и наоборот. Подобное, однако, допускается только в случае использования для этого блока более ограничительного модификатора доступа, чем у того, что определен в интерфейсе. Из-за того, что блоки, определяемые в интерфейсе, изначально имеют уровень доступа public, получается, что добавлять можно только блоки с уровнем, отличным от public. Ниже приведен пример:
public interface IMylnterface
{
int MylntProperty
{
get;
}
}
public class MyBaseClass : IMylnterface
{
protected int mylnt;
public int MylntProperty
{
Get
{
return mylnt;
}
protected set
{
mylnt = value;
}
}