Archiwa blogu
Jawna implementacja interfejsów jako rozwiązanie konfliktu nazw
2012-08-25
Implementując w danej klasie kilka interfejsów możemy spotkać się z sytuacją, w której różne interfejsy będą posiadały składowe o tych samych nazwach:
interface IFirstInterface { void SomeMethod(); } interface ISecondInterface { void SomeMethod(); } class SomeClass : IFirstInterface, ISecondInterface { public void SomeMethod() { Console.WriteLine("Call some method..."); } }
Powyższy kod prezentuje klasę implementującą dwa interfejsy zawierające metody o tej samej nazwie. W klasie metoda zaimplementowana jest raz i działa bez względu na to, za pośrednictwem którego interfejsu zostanie wywołana:
static void Main(string[] args) { SomeClass someClass = new SomeClass(); IFirstInterface iFirst = someClass; ISecondInterface iSecond = someClass; iFirst.SomeMethod(); //Call some method... iSecond.SomeMethod(); //Call some method... Console.ReadLine(); }
A co jeżeli metoda pierwszego interfejsu ma inne przeznaczenie niż metoda drugiego i ich kod powinien być różny? Rozwiązaniem tego problemu jest jawna implementacja interfejsów:
class SomeClass : IFirstInterface, ISecondInterface { void IFirstInterface.SomeMethod() { Console.WriteLine("Call some method from first interface..."); } void ISecondInterface.SomeMethod() { Console.WriteLine("Call some method from second interface..."); } }
W przypadku jawnej implementacji nazwę składowej poprzedzamy nazwą danego interfejsu. Drugą ważną rzeczą jest pominięcie modyfikatora dostępu, ponieważ jawnie implementowana składowa automatycznie otrzymuje modyfikator private i nie można tego zmienić. Fakt ten oznacza, że taka składowa nie będzie dostępna przy odwołaniu z poziomu obiektu a jedynie z poziomu danego interfejsu. Oczywiście w powyższym kodzie można na przykład jawnie zaimplementować jedynie drugi interfejs, dzięki temu pierwsza wersja metody będzie dostępna z poziomu obiektu oraz interfejsu IFirstInterface, natomiast druga wersja jedynie z poziomu interfejsu ISecondInterface. Oto działanie jawnej implementacji:
static void Main(string[] args) { SomeClass someClass = new SomeClass(); IFirstInterface iFirst = someClass; ISecondInterface iSecond = someClass; iFirst.SomeMethod(); //Call some method from first interface... iSecond.SomeMethod(); //Call some method from second interface... Console.ReadLine(); }
Jak widać, wywołując metodę za pośrednictwem wybranego interfejsu, obiekt jest w stanie określić jej odpowiednią wersję. Oprócz rozwiązywania konfliktów nazw, jawną implementację interfejsów można wykorzystać także do ukrywania pewnych elementów klasy przy dostępie z poziomu obiektu. Elementy te będą jednocześnie dostępne przy odwołaniu poprzez interfejs.
Na zakończenie warto dodać, że powinno unikać się sytuacji, w których składowe o tych samych nazwach różnią się przeznaczeniem lub sposobem działania. Jeżeli jednak nie mamy na to wpływu (na przykład korzystamy z bibliotek zewnętrznych) jawna implementacja interfejsów pozwoli nam na rozwiązanie konfliktu nazw.