MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Implementarea explicită a interfețelor

Pe lângă utilizarea implicită a interfețelor, care a fost discutată în articolul anterior, există și implementarea explicită a interfeței. În cazul implementării explicite, se menționează numele metodei sau proprietății împreună cu numele interfeței. În acest caz, nu putem folosi niciun fel de modificatori:

interface IAction
{
   void Move();
}
class BaseAction : IAction
{
   void IAction.Move() => Console.WriteLine("Move in Base Class");
}

Trebuie să avem în vedere că, la implementarea explicită a interfeței, metodele și proprietățile acesteia nu fac parte din interfața clasei. Prin urmare, nu putem accesa direct aceste metode și proprietăți prin obiectul clasei:

BaseAction baseAction1 = new BaseAction();

// baseAction1.Move();  // ! Eroare - în BaseAction nu există metoda Move
// este necesară conversia la tipul IAction
// conversie nesigură
((IAction)baseAction1).Move();  
// conversie sigură
if (baseAction1 is IAction action) action.Move();
// sau așa
IAction baseAction2 = new BaseAction();
baseAction2.Move();

În ce situație poate fi necesară implementarea explicită a interfeței? De exemplu, când o clasă implementează mai multe interfețe, dar acestea au aceeași metodă cu același rezultat și aceiași parametri:

class Person : ISchool, IUniversity
{
   public void Study() => Console.WriteLine("Învățare la școală sau la universitate");
}
interface ISchool
{
   void Study();
}
interface IUniversity
{
   void Study();
}

Clasa Person definește o metodă Study(), creând o implementare comună pentru ambele interfețe aplicate. Indiferent dacă tratăm obiectul Person ca obiect de tip ISchool sau IUniversity, rezultatul metodei va fi același.

Pentru a distinge interfețele implementate, trebuie să aplicăm explicit interfața:

class Person : ISchool, IUniversity
{
   void ISchool.Study() => Console.WriteLine("Învățare la școală");
   void IUniversity.Study() => Console.WriteLine("Învățare la universitate");
}

Utilizare:

Person person = new Person();

((ISchool)person).Study();
((IUniversity)person).Study();

O altă situație este atunci când în clasa de bază interfața este deja implementată, dar este necesară implementarea diferită a acesteia în clasa derivată:

interface IAction
{
   void Move();
}
class BaseAction : IAction
{
   public void Move() => Console.WriteLine("Move in BaseAction");
}
class HeroAction : BaseAction, IAction
{
   void IAction.Move() => Console.WriteLine("Move in HeroAction");
}

Deși clasa de bază BaseAction a implementat deja interfața IAction, clasa derivată o implementează în mod diferit. Utilizarea claselor:


HeroAction action1 = new HeroAction();
action1.Move();            // Move in BaseAction
((IAction)action1).Move(); // Move in HeroAction

IAction action2 = new HeroAction();
action2.Move();            // Move in HeroAction

Modificatori de acces

Membrii interfeței pot avea diferiți modificatori de acces. Dacă modificatorul de acces nu este public, ci altul, atunci la implementarea metodei, proprietății sau evenimentului interfeței în clase și structuri, putem folosi două metode. În primul rând, putem folosi și implementarea explicită a interfeței, implementând toate necesitățile interfeței fără modificatori de acces:

IMovable tom = new Person("Tom");
// abonare la eveniment
tom.MoveEvent += () => Console.WriteLine($"{tom.Name} is moving");
tom.Move();

delegate void MoveHandler();    // delegat de mișcare
interface IMovable
{
   protected internal void Move();
   protected internal string Name { get; }
   protected internal event MoveHandler MoveEvent;
}
class Person : IMovable
{
   string name;
   // implementarea explicită a evenimentului - se creează o variabilă suplimentară
   MoveHandler? moveEvent;
   event MoveHandler IMovable.MoveEvent
   {
       add => moveEvent += value;
       remove => moveEvent -= value;
   }
   // implementarea explicită a proprietății - ca auto-proprietate
   string IMovable.Name { get => name; }
   public Person(string name) => this.name = name;
   // implementarea explicită a metodei
   void IMovable.Move()
   {
       Console.WriteLine($"{name} is walking");
       moveEvent?.Invoke();
   }
}

În acest caz, trebuie să avem în vedere că putem accesa direct aceste metode, proprietăți și evenimente doar prin variabila interfeței, nu prin variabila clasei.

O alternativă o reprezintă implementarea implicită cu modificatorul public:

Person tom = new Person("Tom");
// abonare la eveniment
tom.MoveEvent += () => Console.WriteLine($"{tom.Name} is moving");
tom.Move();

delegate void MoveHandler();

interface IMovable
{
   protected internal void Move();
   protected internal string Name { get; }
   protected internal event MoveHandler MoveEvent;
}
class Person : IMovable
{
   string name;
   // implementarea explicită a evenimentului - se creează o variabilă suplimentară
   MoveHandler? moveEvent;
   // implementarea implicită a evenimentului cu modificatorul public
   public event MoveHandler MoveEvent
   {
       add => moveEvent += value;
       remove => moveEvent -= value;
   }
   // implementarea implicită a proprietății - ca auto-proprietate, dar cu modificatorul public
   public string Name { get => name; }
   public Person(string name) => this.name = name;
   // implementarea implicită a metodei, dar cu modificatorul public
   public void Move()
   {
       Console.WriteLine($"{name} is walking");
       moveEvent?.Invoke();
   }
}

În acest caz, metodele, proprietățile și evenimentele interfeței pot fi accesate prin variabila clasei.

← Lecția anterioară Lecția următoare →