Używanie interfejsów na klasach abstrakcyjnych w C#

Uczę się C # Z C++ i wpadłem na ścianę.

Mam klasę abstrakcyjną AbstractWidget, interfejs IDoesCoolThings i klasę, która wywodzi się z AbstractWidget o nazwie RealWidget:

public interface IDoesCoolThings
{
    void DoCool();
}

public abstract class AbstractWidget : IDoesCoolThings
{
    void IDoesCoolThings.DoCool()
    {
        Console.Write("I did something cool.");
    }
}

public class RealWidget : AbstractWidget
{

}

Kiedy uruchamiam obiekt RealWidget i wywołuję na nim docool (), kompilator wyświetla mi błąd:

'RealWidget' nie zawiera definicja dla "DoCool"

Mogę rzucić obiekt RealWidget na IDoesCoolThings, a następnie wywołanie będzie działać, ale to wydaje się niepotrzebne i tracę też polimorfizm (AbstractWidget.Docool () będzie zawsze wywoływana, nawet jeśli zdefiniuję RealWidget.DoCool ()).

Wyobrażam sobie, że rozwiązanie jest proste, ale próbowałem różnych rzeczy i na całe życie nie mogę tego rozgryźć.

Author: JubJub, 2009-03-26

4 answers

Wpadasz w problem, ponieważ użyłeś explicit interface implementation (EII). Gdy członek jest jawnie zaimplementowany, nie można uzyskać do niego dostępu przez instancję klasy - tylko przez instancję interfejsu. W twoim przykładzie, dlatego nie możesz wywołać DoCool(), chyba że oddasz swoją instancję do IDoesCoolThings.

Rozwiązaniem jest upublicznienie DoCool() i usunięcie jawnej implementacji interfejsu:

public abstract class AbstractWidget : IDoesCoolThings
{
    public void DoCool()      // DoCool() is part of the abstract class implementation.
    {
        Console.Write("I did something cool.");
    }
}

// ...

var rw = new RealWidget();
rw.DoCool();                  // Works!

Ogólnie, używasz EII w dwóch przypadki:

  • masz klasę, która musi zaimplementować dwa interfejsy, z których każdy zawiera członka, który ma identyczną nazwę/podpis do innego członka w innym interfejsie.
  • chcesz zmusić klientów, aby nie polegali na szczegółach implementacji twojej klasy, ale raczej na interfejsie, który jest implementowany przez Twoją klasę. (Jest to przez niektórych uważane za dobrą praktykę.)
 42
Author: John Feminella,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-26 02:45:33

Zmień deklarację na:

public abstract class AbstractWidget : IDoesCoolThings 
{
    public void DoCool()
    { 
        Console.Write("I did something cool."); 
    }
}
 8
Author: Mitch Wheat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-25 18:37:02

Sposób implementacji interfejsu jest jawny implementacja Void IDoesCoolThings.DoCool (), jeśli wybierzesz implicit implementation interface.

public abstract class AbstractWidget : IDoesCoolThings
{
    public void DoCool()
    {
        Console.Write("I did something cool.");
    }
}
Wtedy zadziała.

Przeczytaj to:

Interfejsy C#. Implicit implementation versus Explicit implementation

 7
Author: J.W.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:09:21

Powinieneś to zrobić w ten sposób:

public interface IDoesCoolThings 
{
   void DoCool();
}

public abstract class AbstractWidget 
{
   public void DoCool()
   {
      Console.WriteLine("I did something cool.");
   }
}

public class Widget : AbstractWidget, IDoesCoolThings 
{
}

Użycie:

var widget = new Widget();
widget.DoCool();
 1
Author: Toffee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-15 17:35:32