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źć.
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ę.)
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.");
}
}
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
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();
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