Jak mogę wywołać metodę domyślną zamiast konkretnej implementacji

9

Dlaczego zachowanie domyślnych metod interfejsu zostało zmienione w C # 8? W przeszłości następujący kod (gdy domyślne metody interfejsu nie były udostępniane):

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();
    }
}

ma następujące dane wyjściowe:

Dane wyjściowe konsoli:

Jestem domyślną metodą w interfejsie!
Jestem przesłoniętą metodą domyślną!

Ale w ostatniej wersji C # 8 powyższy kod generuje następujące dane wyjściowe:

Dane wyjściowe konsoli:

Jestem przesłoniętą metodą domyślną!
Jestem przesłoniętą metodą domyślną!

Czy ktoś może mi wyjaśnić, dlaczego to zachowanie się zmieniło?

Uwaga:

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

((IDefaultInterfaceMethod) anyClass).DefaultMethod(); // STILL the same problem!??
Bassam Alugili
źródło
2
Nie było domyślnych metod interfejsu przed C # 8. Drugim wyjściem jest oczekiwany przypadek - kiedy implementujesz metodę interfejsu, oczekujesz, że zostanie wywołana. Masz na myśli starszą specyfikację? Oczekuję, że został porzucony, ponieważ psuje oczekiwane zachowanie metody interfejsu
Panagiotis Kanavos
3
Lepszym pytaniem byłoby „jak mogę wywołać metodę domyślną zamiast konkretnej implementacji?” na które odpowiedź brzmi: „jeszcze nie możesz, ponieważ składnia base.DefaultMethod () została usunięta z C # 8”
Panagiotis Kanavos
4
Oto strona spotkania projektowego, na której omówiono połączenia bazowe dla C # 8 Cut base() syntax for C# 8. We intend to bring this back in the next major release.. Wymagałoby to wsparcia środowiska wykonawczego do poprawnego działania.
Panagiotis Kanavos
3
Interfejs jest interfejsem zawsze. Po wdrożeniu metody interfejsu oczekuję, że wszyscy klienci będą wywoływać zaimplementowaną metodę. Klienci nie powinni również dbać o to, która klasa implementuje metodę - mają interfejs i nazywają go.
Panagiotis Kanavos
2
Jeśli chodzi o opublikowaną składnię, musi to być naprawdę stara propozycja - moduły DIM można wywoływać tylko jawnie, podobnie jak jawnie zaimplementowane interfejsy. Propozycja ta jednak używa składni interfejsu wyraźny do ... wykonaj naprzeciwko od virtualChyba? I ewentualnie wprowadzenie diamentu spadkowego
Panagiotis Kanavos

Odpowiedzi:

6

Podejrzewam, że lepszym pytaniem byłoby:

Jak mogę wywołać metodę domyślną zamiast konkretnej implementacji?

Ta funkcja została zaplanowana, ale została usunięta z C # 8 w kwietniu 2019 r. , Ponieważ wydajne wdrożenie wymagałoby wsparcia ze strony środowiska wykonawczego. Nie można tego dodać na czas przed wydaniem. Ta funkcja musiałaby działać dobrze zarówno dla C #, jak i VB.NET - F # i tak nie lubi interfejsów.

jeśli BM nie jest obecny w czasie wykonywania, zostanie wywołana AM (). W przypadku base () i interfejsów nie jest to obsługiwane przez środowisko wykonawcze, dlatego wywołanie spowoduje zgłoszenie wyjątku. Chcielibyśmy dodać obsługę tego w środowisku wykonawczym, ale wykonanie tej wersji jest zbyt drogie.

Mamy pewne obejścia, ale nie zachowują się tak, jak chcemy, i nie są preferowanym kodegenem.

Nasza implementacja w języku C # jest w pewnym stopniu wykonalna, chociaż nie dokładnie tak, jak byśmy chcieli, ale implementacja VB byłaby znacznie trudniejsza. Ponadto implementacja dla VB wymagałaby, aby metody implementacji interfejsu były publiczną powierzchnią API.

Będzie działał przez base()wywołanie podobne do działania klas. Kopiowanie przykładu propozycji:

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
źródło
Zostawię to na chwilę, zanim zaznaczę odpowiedź. może dostaniesz trochę głosów za dobrą pracę :-) dziękuję!
Bassam Alugili
1
@BassamAlugili tylko dlatego, że ktoś zapytał o coś podobnego miesiąc temu. Wtedy myślałem Why would you do that?. Potem dowiedziałem się o spotkaniu
Panagiotis Kanavos