Jawna i niejawna implementacja interfejsu w C#

Interfejs klasy — w obiektowych językach programowania interfejs jest abstrakcyjną reprezentacją klasy pozwalającą na korzystanie z niej niezależnie od faktycznej implementacji. Interfejs pozwala na enkapsulację wielu różnych obiektów utworzonych w oparciu o odmienne klasy, które zawierają implementację wspólnego interfejsu. [wikipedia]
Interfejs dostarcza nam pewną funkcjonalność którą realizują klasy implementujące go, dzięki czemu możemy posługiwać się wyłącznie interfejsem aby zrealizować konkretne zadania bez konieczności zagłębiania się w kod znajdujący się za nimi.

Interfejsy w C#

W języku C# definiując interfejs posługujemy się słowem kluczowym interface, trzeba pamiętać że przy tworzeniu interfejsu nie używamy modyfikatorów dostępu, gdyż wszystkie elementy zawarte w interfejsie są publiczne. W interfejsach tworzymy jedynie definicje wybranych elementów które muszą zaimplementować klasy/struktury je implementujące.

Interfejsy mogą zawierać deklarację:

  • metod
  • właściwości
  • zdarzeń
  • indekserów

Interfejsy nie mogą zawierać stałych, pól, operatorów, konstruktorów, destruktorów i zagnieżdżonych typów. Nie mogą zawierać również statycznych elementów.

Interfejsy mogą dziedziczyć po jednym lub kilku interfejsach. Elementami implementującymi interfejsy są klasy lub struktury (mogą on implementować wiele interfejsów). W języku C# mamy również możliwość tworzenia generycznych interfejsów.

Niejawna implementacja interfejsu

Niejawna implementacja interfejsu jest najbardziej znaną formą implementacji. Polega ona na  zaimplementowaniu publicznych elementów których definicje zawiera interfejs:

[csharp]
interface ISampleInterface1
{
void Print();
string Message { get; }
}
interface ISampleInterface2
{
void Print();
}
class SampleClass : ISampleInterface1, ISampleInterface2
{
// Zarówno ISampleInterface1.Print i ISampleInterface2.Print
// wywołają tą metodę
public void Print()
{
Console.WriteLine("Metoda Print");
}
private string _message = "";
public string Message
{
get { return _message; }
set { _message = value; }
}
}
[/csharp]

Jak widzimy nie ma tu żadnej magi implementujemy w klasie SampleClass metodę Print i właściwość Message z interfejsu ISampleInterface1 do której dopisujemy setter.

Jawna implementacja interfejsu

Aby jawnie zaimplementować interfejs musimy nazwę implementowanego elementu poprzedzić nazwą interfejsu:

[csharp]
class SampleClass : ISampleInterface1, ISampleInterface2
{
void ISampleInterface1.Print()
{
Console.WriteLine("ISampleInterface1.Print");
}

void ISampleInterface2.Print()
{
Console.WriteLine("ISampleInterface2.Print");
}

private string _message = "";
string ISampleInterface1.Message
{
get { return _message; }
}
}
[/csharp]

Dzięki jawnej implementacji mamy możliwość zaimplementowani dwóch metod o tej samej nazwie co czasami może być niezmiernie przydatne. Przy jawnej implementacji trzeba pamiętać, że nie możemy używać modyfikatorów dostępu. Z jawną implementacją wiąże się też kilka niedogodności: implementacje elementów interfejsu nie są widoczne w klasie implementujące, aby uzyskać do nich dostęp musimy posługiwać się konkretny interfejsem. W przypadku właściwości Message nie możemy dopisać settera gdyż dostaniemy błąd kompilacji.

Więcej informacji na temat interfejsów można uzyskać w:
Interfaces (C# Programming Guide), Explicit Interface Implementation, Explicit Interface Implementation Tutorial, Implicit and Explicit Interface Implementations, Design Guideline Update: Explicit Member Implementation, Interface layout, Interface (C# Reference),