Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Wykład 5
Interfejsy
dr inż. Maciej Kusy
Katedra Podstaw Elektroniki
Wydział Elektrotechniki i Informatyki
Politechnika Rzeszowska
Programowanie w języku C#
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Plan wykładu
• Pojęcie interfejsu, właściwości interfejsów
• Definiowanie i implementowanie interfejsu
• Implementacja kilku interfejsów
• Łączenie i rozszerzanie interfejsu
• Dostęp do metod interfejsu
• Rzutowanie na interfejs
• Operator is i operator as
• Interfejsy kontra klasy abstrakcyjne
• Przesłanianie implementacji interfejsu
• Jawna implementacja interfejsu
2
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Interfejs
Interfejs to nazwa grupy metod. Z perspektywy interfejsu nie jest ważna definicja tych metod – ważna jest tylko ich sygnatura: (nazwa, argumenty) oraz typ wartości zwracanej.
Interfejs definiuje zachowanie klasy – można to ująć
słowami: „ potrafi robić” – jest to relacja implementacji.
W definicji interfejsu, można podać deklaracje metody, właściwości, mechanizmu indeksującego (indeksera) lub
zdarzenia.
Interfejs nie może natomiast zawierać deklaracji żadnych pól!
3
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Właściwości interfejsów:
• Interfejs nie może dziedziczyć po klasie.
• Interfejs może rozszerzać wiele interfejsów.
• Klasa może implementować wiele interfejsów (ale może dziedziczyć tylko po jednej klasie).
• Żadna z metod zadeklarowanych w interfejsie nie może mieć nim w implementacji.
• Przy deklaracji składowej interfejsu nie używamy
modyfikatora dostępu – składowe interfejsu są publiczne.
• Przy deklaracjach składowych nie można również użyć innych modyfikatorów, tj.: virtual, abstract, override.
• Nazwa interfejsu powinna rozpoczynać się od litery I (konwencja).
• Implementacja interfejsu polega na zdefiniowaniu wszystkich jego składowych w klasie, która go implementuje.
4
• Struktury mogą implementować interfejsy.
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Definicja i implementacja interfejsu
interface IPrzechowalnia
{
void Zapisz();
}
class Dokument : IPrzechowalnia
{
public Dokument() {/*...*/}
public void Zapisz()
{
//Ciało metody
}
}
5
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Implementacja kilku interfejsów
interface IA
{
void WypiszA();
}
interface IB
{
void WypiszB();
}
class C : IA, IB
{
public void WypiszA(){/*... */}
public void WypiszB(){/*... */}
}
6
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Łączenie i rozszerzanie interfejsów
interface IA { void MetodaA(); }
interface IB { void MetodaB(); }
interface IC { void MetodaC(); }
interface ID : IA, IB { void MetodaD(); }
class E : IC, ID
{
public void MetodaC(){/*... */}
public void MetodaA(){/*... */}
public void MetodaB(){/*... */}
public void MetodaD(){/*... */}
}
7
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Dostęp do metod interfejsu
Można stworzyć egzemplarz interfejsu rzutując go na dany typ.
Odpowiednią referencję wskazującą na obiekt implementujący interfejs:
Dokument dok = new Dokument();
IPrzechowalnia iDok = dok;
iDok.Zapisz();
IPrzechowalnia iDok2 = new Dokument();
Nie można bezpośrednio stworzyć egzemplarza interfejsu: IPrzechowlania iDok3 = new IPzechowalnia();
8
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Rzutowanie na interfejs
Często nie wiadomo, czy typ (klasa) implementuje dany
interfejs.
W takich wypadkach należy zrzutować obiekt klasy na
dany interfejs:
Dokument dok = new Dokument();
IPrzechowalnia iDok = (IPrzechowalnia) dok;
iDok.Zapisz();
W przypadku gdy klasa nie implementuje interfejsu,
rzutowanie jest niepoprawne i zostanie zgłoszony wyjątek: System.InvalidCastException.
Jak to bezpiecznie sprawdzić? Zastosować operator is.
9
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Operator is
Aby wywołać odpowiednią metodę interfejsu na rzecz obiektu, należy sprawdzić, czy klasa tego obiektu implementuje dany interfejs. Jednym z rozwiązań jest zastosowanie operatora is: Dokument dok = new Dokument();
if(dok is IPrzechowlania)
{
IPrzechowalnia iDok = (IPrzechowalnia) dok;
}
Operator is zwraca true jeżeli wyrażenie w instrukcji if (musi być typem referencyjnym) można bezpiecznie rzutować bez zgłoszenia wyjątku.
10
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Operator as
Operator as jest rozszerzeniem operatora is – sprawdza czy dane rzutowanie jest dozwolone (czyli czy operator is zwraca true) i jeżeli warunek jest spełniony – wykonuje rzutowanie.
Dokument dok = new Dokument();
IPrzechowalnia iDok = dok as IPrzechowalnia;
if(iDok != null)
{
//rzutowanie jest dozwolone
}
Operator as eliminuje potrzebę obsługi wyjątku. Jeżeli adres egzemplarza interfejsu jest różny od adresu zerowego, to rzutowanie jest możliwe, bo dana klasa implementuje interfejs.
11
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Interfejsy kontra klasy abstrakcyjne
• Interfejs definiuje zachowanie klasy („ potrafi robić”), klasa pochodna po klasie abstrakcyjnej jest „ tego samego typu”, co jej klasa bazowa.
• Interfejsy w przeciwieństwie do klas abstrakcyjnych dają możliwość wielokrotnego rozszerzania (dziedziczenia).
• Dodanie nowej metody do interfejsu wiąże się z
koniecznością dostosowania wszystkich klas, które ten
interfejs implementują.
• Dodanie nowej metody do abstrakcyjnej klasy bazowej nie wprowadza żadnego zamieszania – wystarczy nową metodę
zadeklarować jako wirtualną z domyślną implementacją.
• Jeżeli klasa dziedziczy po jakiejś klasie i implementuje kilka interfejsów, to nazwa klasy musi wystąpić jako
pierwsza na liście dziedziczenia.
12
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Przesłanianie implementacji interfejsu
W klasie obsługującej interfejs, metody interfejsu można oznaczyć jako wirtualne.
W klasach pochodnych można wtedy przesłaniać
implementacje tych metod.
Dzięki temu możliwe jest używanie metod klas w hierarchii dziedziczenia w sposób polimorficzny za pomocą obiektu interfejsu.
13
Programowanie w języku C#. Maciej Kusy, mkusy@prz.edu.pl Jawna implementacja interfejsu
Co dzieje się w przypadku, gdy klasa implementuje kilka interfejsów, w których znajdują się metody o tej samej nazwie?
interface IA { void Metoda(); }
interface IB { void Metoda(); }
class C : IA, IB {/* ??? */}
Odpowiedź: w klasie musi znaleźć się jawna implementacja każdej z metod:
class C : IA, IB
{
void IA.Metoda(){} //metoda niejawnie publiczna void IB.Metoda(){} //nie można użyć mod. public
}
14