Wie kann ich die Standardmethode anstelle der konkreten Implementierung aufrufen?

9

Warum wird das Verhalten der Standardschnittstellenmethoden in C # 8 geändert? In der Vergangenheit der folgende Code (als die Standardschnittstellenmethoden Demo nicht veröffentlicht wurden):

interface IDefaultInterfaceMethod
{
    // By default, this method will be virtual, and the virtual keyword can be here used!
    virtual void DefaultMethod()
    {
        Console.WriteLine("I am a default method in the interface!");
    }

}

interface IOverrideDefaultInterfaceMethod : IDefaultInterfaceMethod
{
    void IDefaultInterfaceMethod.DefaultMethod()
    {
        Console.WriteLine("I am an overridden default method!");
    }
}

class AnyClass : IDefaultInterfaceMethod, IOverrideDefaultInterfaceMethod
{
}

class Program
{
    static void Main()
    {
        IDefaultInterfaceMethod anyClass = new AnyClass();
        anyClass.DefaultMethod();

        IOverrideDefaultInterfaceMethod anyClassOverridden = new AnyClass();
        anyClassOverridden.DefaultMethod();
    }
}

hat folgende Ausgabe:

Konsolenausgabe:

Ich bin eine Standardmethode in der Schnittstelle!
Ich bin eine überschriebene Standardmethode!

Mit der letzten Version von C # 8 erzeugt der obige Code jedoch die folgende Ausgabe:

Konsolenausgabe:

Ich bin eine überschriebene Standardmethode!
Ich bin eine überschriebene Standardmethode!

Kann mir jemand erklären, warum sich dieses Verhalten ändert?

Hinweis:

IDefaultInterfaceMethod anyClass = new AnyClass(); anyClass.DefaultMethod();

((IDefaultInterfaceMethod) anyClass).DefaultMethod(); // STILL the same problem!??
Bassam Alugili
quelle
2
Vor C # 8 gab es keine Standardschnittstellenmethoden . Die zweite Ausgabe ist der erwartete Fall. Wenn Sie eine Schnittstellenmethode implementieren, erwarten Sie, dass diese aufgerufen wird. Beziehen Sie sich vielleicht auf eine ältere Spezifikation? Ich gehe davon aus, dass es aufgegeben wurde, weil es das erwartete Verhalten einer Schnittstellenmethode
Panagiotis Kanavos
3
Eine bessere Frage wäre: "Wie kann ich die Standardmethode anstelle der konkreten Implementierung aufrufen?" worauf die Antwort lautet "Sie können noch nicht, weil die base.DefaultMethod () -Syntax von C # 8 entfernt wurde"
Panagiotis Kanavos
4
Hier ist die Design-Meeting-Seite, auf der Basisanrufe besprochen und für C # 8 gelöscht wurden Cut base() syntax for C# 8. We intend to bring this back in the next major release.. Dies würde Laufzeitunterstützung erfordern, um richtig zu funktionieren.
Panagiotis Kanavos
3
Eine Schnittstelle ist immer eine Schnittstelle. Wenn ich eine Schnittstellenmethode implementiere, erwarte ich, dass alle Clients die implementierte Methode aufrufen. Clients sollten sich auch nicht darum kümmern, welche Klasse die Methode implementiert - sie haben eine Schnittstelle und rufen sie auf.
Panagiotis Kanavos
2
Die von Ihnen veröffentlichte Syntax muss aus einem wirklich alten Vorschlag stammen. DIMs können nur explizit aufgerufen werden, wie explizit implementierte Schnittstellen. Dieser Vorschlag verwendet jedoch die explizite Schnittstellensyntax, um ... das Gegenteil von virtualIch denke? Und möglicherweise einen Erbschaftsdiamanten einführen
Panagiotis Kanavos

Antworten:

6

Ich vermute, eine bessere Frage wäre:

Wie kann ich die Standardmethode anstelle der konkreten Implementierung aufrufen?

Das Feature war geplant, wurde jedoch im April 2019 von C # 8 gestrichen , da für eine effiziente Implementierung Unterstützung zur Laufzeit erforderlich wäre. Dies konnte nicht rechtzeitig vor der Veröffentlichung hinzugefügt werden. Die Funktion müsste sowohl für C # als auch für VB.NET gut funktionieren - F # mag sowieso keine Schnittstellen.

Wenn BM zur Laufzeit nicht vorhanden ist, wird AM () aufgerufen. Für base () und Schnittstellen wird dies von der Laufzeit nicht unterstützt, sodass der Aufruf stattdessen eine Ausnahme auslöst. Wir möchten dies zur Laufzeit unterstützen, aber es ist zu teuer, diese Version zu erstellen.

Wir haben einige Problemumgehungen, aber sie haben nicht das gewünschte Verhalten und sind nicht der bevorzugte Codegen.

Unsere Implementierung für C # ist einigermaßen praktikabel, obwohl nicht genau das, was wir möchten, aber die VB-Implementierung wäre viel schwieriger. Darüber hinaus würde die Implementierung für VB erfordern, dass die Schnittstellenimplementierungsmethoden eine öffentliche API-Oberfläche sind.

Es funktioniert über einen base()Aufruf , der der Funktionsweise von Klassen ähnelt. Kopieren des Beispielvorschlags:

interface I1
{ 
    void M(int) { }
}

interface I2
{
    void M(short) { }
}

interface I3
{
    override void I1.M(int) { }
}

interface I4 : I3
{
    void M2()
    {
        base(I3).M(0) // What does this do?
    }
}
Panagiotis Kanavos
quelle
Ich werde es für eine Weile verlassen, bevor ich die Antwort markiere. Vielleicht bekommst du ein paar Up-Votes für deine gute Arbeit :-) Danke!
Bassam Alugili
1
@BassamAlugili nur, weil jemand vor einem Monat etwas Ähnliches gefragt hat. Damals dachte ich allerdings Why would you do that?. Dann fand ich das Sitzungsprotokoll heraus
Panagiotis Kanavos