2010-10-20 29 views
18

Czy istnieje konstrukt w języku Java lub C#, który wymusza dziedziczenie klas w celu wywołania podstawowej implementacji? Możesz wywołać super() lub base(), ale czy jest możliwe, aby rzucił błąd podczas kompilacji, jeśli nie zostanie wywołany? To byłoby bardzo wygodne ..Wywołanie metody Force base

--edit--

Jestem ciekawy głównie o przesłanianie metod.

+0

Czy to znaczy od konstruktora gdy przesłanianie metody? – munificent

Odpowiedz

12

Nie ma i nie powinno być w tym nic.

Najbliższy rzeczą mogę myśleć off strony, jeśli coś jak o tym w klasie bazowej:

public virtual void BeforeFoo(){} 

public void Foo() 
{ 

this.BeforeFoo(); 
//do some stuff 
this.AfterFoo(); 

} 

public virtual void AfterFoo(){} 

i pozwolić klasa dziedziczenia override BeforeFoo i/lub AfterFoo

+5

To, co sugerujesz, wydaje się być wspólnym rozwiązaniem problemu. Chociaż posiadanie go (lub automatycznie wywoływane) przez klasę dziedziczącą w celu wywoływania go byłoby wygodne i sprawiłoby, że pewne błędy byłyby łatwe do znalezienia. Czy mógłbyś wyjaśnić, dlaczego * nie powinna * mieć jakąś funkcję, która to robi? Czy jest to sprzeczne z podstawowymi koncepcjami polimorfizmu, a jeśli tak, to dlaczego? – irwinb

+0

Jeśli mam klasę, która rozszerza kolejną klasę, która zmusza mnie do wywoływania base.Foo() gdzieś w moim Foo, to raczej ogranicza. Mogę albo wywołać base.Foo(), jeśli chcę tę funkcjonalność, albo nie mogę użyć tej klasy do rozszerzenia mojej. Kompilator powinien wymusić minimalny zestaw podstawowych zasad. Powinieneś sprawdzić umowy na kod dla .NET http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx – MStodd

0

Nie myśl, że istnieje jakieś możliwe rozwiązanie wbudowane. Jestem pewien, że można to zrobić za pomocą oddzielnych narzędzi do analizy kodu.

0

EDYCJA Błędna konstrukcja jako konstruktor. Pozostawienie jako CW, ponieważ pasuje do bardzo ograniczonego podzbioru problemu.

W języku C# można wymusić to zachowanie, definiując pojedynczy konstruktor mający co najmniej jeden parametr w typie podstawowym. Usuwa to domyślny konstruktor i wymusza typy pochodne, aby wywoływać explicite określoną bazę lub wystąpią błędy kompilacji.

class Parent { 
    protected Parent(int id) { 
    } 
} 

class Child : Parent { 
    // Does not compile 
    public Child() {} 
    // Also does not compile 
    public Child(int id) { } 
    // Compiles 
    public Child() :base(42) {} 

} 
+0

Wierzę, że to działa również w Javie. – BoltClock

+0

Myślę, że OP mówi o tym, że może wymusić "publiczne obejście" void Method() {base.Method(); ...} ', nie o konstruktorach. – Ani

+0

Działa to jednak tylko w przypadku konstruktorów. –

6

Nie w Javie. To może być możliwe w C#, ale ktoś inny będzie musiał z tym porozmawiać.

Jeśli dobrze rozumiem, chcesz to:

class A { 
    public void foo() { 
     // Do superclass stuff 
    } 
} 

class B extends A { 
    public void foo() { 
     super.foo(); 
     // Do subclass stuff 
    } 
} 

Co można zrobić w Javie, aby wymusić korzystanie z nadklasy foo jest coś takiego:

class A { 
    public final void foo() { 
     // Do stuff 
     ... 
     // Then delegate to subclass 
     fooImpl(); 
    } 

    protected abstract void fooImpl(); 
} 

class B extends A { 
    protected void fooImpl() { 
     // Do subclass stuff 
    } 
} 

Jest brzydki, ale osiąga co chcesz. W przeciwnym razie musisz być ostrożny, aby upewnić się, że nazywasz metodę nadklasy.

Może mógłbyś majstrować przy swoim projekcie, aby rozwiązać problem, zamiast używać rozwiązania technicznego. To może nie być możliwe, ale prawdopodobnie warto o tym myśleć.

EDYCJA: Może źle zrozumiałem pytanie. Czy mówisz tylko o konstruktorach lub metodach? Zakładałem ogólnie metody.

+1

+1: Nie sądzę, że jest brzydka. Jest to szablon metody szablonowej i właściwe podejście. Nazwa fooImpl() jest brzydka, ale to tylko przykład ... –

0

w Javie, kompilator może to tylko wymusić w przypadku konstruktorów.

Konstruktor musi być wywołany aż do łańcucha dziedziczenia. Jeśli więc pies rozszerza zwierzę, to musi on wywołać konstruktora, ponieważ Animal musi wywołać konstruktora dla Thing.

Nie dotyczy to zwykłych metod, w których programista musi jawnie wywołać superpoprawkę, jeśli to konieczne.

Jedynym sposobem, aby wymusić jakiś kod implementacji podstawa do uruchomienia jest podział kodu zastąpić zdolnego do osobnego wezwania metoda:

public class Super 
{ 
    public final void doIt() 
    { 
    // cannot be overridden 
     doItSub(); 
    } 

    protected void doItSub() 
    { 
    // override this 
    } 
} 

public class Sub extends Super 
{ 
    protected void doItSub() 
    { 
    // override logic 
    } 
} 
2

Jeśli dobrze rozumiem, chcesz wymusić, że zachowanie klasy bazowej jest nie został przesłonięty, ale nadal byłby w stanie go rozszerzyć, wtedy użyłbym wzoru szablonu metody szablonowej, aw C# nie uwzględnił wirtualnego słowa kluczowego w definicji metody.

1

Nie. Nie jest to możliwe. Jeśli trzeba mieć funkcję, która robi trochę przed lub po działań zrobić coś takiego:

internal class Class1 
{ 
    internal virtual void SomeFunc() 
    { 
     // no guarantee this code will run 
    } 


    internal void MakeSureICanDoSomething() 
    { 
     // do pre stuff I have to do 

     ThisCodeMayNotRun(); 

     // do post stuff I have to do 
    } 

    internal virtual void ThisCodeMayNotRun() 
    { 
     // this code may or may not run depending on 
     // the derived class 
    } 
} 
0

Natknąłem się na tym stanowisku i niekoniecznie podoba mi się żadna konkretna odpowiedź, więc pomyślałem, że dostarczę własną ...

W C# nie ma sposobu na wymuszenie wywołania metody bazowej. Dlatego też kodowanie jako takie jest uważane za antystopkę, ponieważ dalszy deweloper może nie zdawać sobie sprawy, że musi wywołać metodę bazową, jeśli klasa będzie w stanie niekompletnym lub złym.

Jednakże znalazłem okoliczności, w których ten typ funkcjonalności jest wymagany i można go odpowiednio spełnić. Zwykle klasa pochodna potrzebuje zasobu klasy bazowej. Aby uzyskać zasób, który normalnie może być eksponowany za pośrednictwem właściwości, jest on wyeksponowany za pomocą metody. Klasa pochodna nie ma innego wyjścia, niż wywołać metodę uzyskiwania zasobu, zapewniając w ten sposób wykonanie metody klasy podstawowej.

Następne logiczne pytanie, które można zadać, brzmi: dlaczego nie umieścić go w konstruktorze? Powodem jest to, że może to być kolejność operacji. W czasie, gdy klasa jest skonstruowana, może jeszcze brakować danych wejściowych.

Czy to urywa się od pytania? Tak i nie. Tak, wymusza na klasie pochodnej wywoływanie konkretnej metody klasy bazowej. Nie, nie robi tego ze słowem kluczowym override. Może to być pomocne dla osoby szukającej odpowiedzi na ten post.

Nie nauczam tego jako ewangelii, a jeśli ktoś widzi wady tego podejścia, bardzo chciałbym o tym usłyszeć.

1

Nie przeczytałem WSZYSTKICH odpowiedzi tutaj; jednak rozważałem to samo pytanie. Po przejrzeniu tego, co NAPRAWDĘ chciałem zrobić, wydawało mi się, że jeśli chcę WYMAGAĆ połączenia z metodą podstawową, nie powinienem zadeklarować w zasadzie metody bazowej wirtualnej (nadpisującej).

2

Poniższy przykład wyrzuca InvalidOperationException, gdy podstawowa funkcjonalność nie jest dziedziczona podczas przesłonięcia metody.

Może to być przydatne w scenariuszach, w których metoda jest wywoływana przez niektóre wewnętrzne interfejsy API.

tj.gdzie Foo() nie jest przeznaczony do powoływać bezpośrednio:

public abstract class ExampleBase { 
    private bool _baseInvoked; 

    internal protected virtual void Foo() { 
     _baseInvoked = true; 
     // IMPORTANT: This must always be executed! 
    } 

    internal void InvokeFoo() { 
     Foo(); 
     if (!_baseInvoked) 
      throw new InvalidOperationException("Custom classes must invoke `base.Foo()` when method is overridden."); 
    } 
} 

działa:

public class ExampleA : ExampleBase { 
    protected override void Foo() { 
     base.Foo(); 
    } 
} 

krzyczy:

public class ExampleB : ExampleBase { 
    protected override void Foo() { 
    } 
} 
Powiązane problemy