2013-01-25 24 views
50

Załóżmy, że jeśli mam interfejs jak określono poniżej:C# Interfejs Dziedziczenie do klasy abstrakcyjnej

public interface IFunctionality 
{ 
    void Method();  
} 

i implementować ten interfejs dla klasy abstrakcyjnej, jak pokazano poniżej:

public abstract class AbstractFunctionality: IFunctionality 
{ 
    public void Method() 
    { 
     Console.WriteLine("Abstract stuff" + "\n"); 
    }  
} 

znowu mam klasa betonu, która dziedziczy z klasy abstrakcyjnej, jak poniżej:

public class ConcreteFunctionality: AbstractFunctionality 
{ 
    public void Method() 
    { 
     Console.WriteLine("Concrete stuff" + "\n"); 
    } 
} 

Teraz mam następującą ofertę de,

ConcreteFunctionality mostDerived = new ConcreteFunctionality(); 
AbstractFunctionality baseInst = mostDerived; 
IFunctionality interfaceInst = mostDerived; 
mostDerived.Method(); 
baseInst.Method(); 
interfaceInst.Method(); 

Dane wyjściowe, które otrzymuję po wykonaniu tych czynności są następujące.

Concrete stuff 
Abstract stuff 
Abstract stuff 

Ale to, co zostało oczekując wyjście będzie „konkretne rzeczy” we wszystkich trzech przypadkach, co robię tutaj jest przypisanie odniesienie ConcreteFunctionality do zmiennych typu AbstractFunctionality i IFunctionality.

Co dzieje się wewnętrznie. Uprzejmie wyjaśnij.

+2

To może wyjaśnić coś więcej: http://stackoverflow.com/questions/392721/difference-between- shadowing-and-overriding-in-c- – Stormenet

+0

"Jest ukryty, nie przesłonięty" - dobra mantra do zapamiętania. (Ale twój kompilator powinien o tym wspomnieć, czy masz odfiltrowane ostrzeżenia?) – kmote

Odpowiedz

74

tutaj:

public class ConreteFunctionality:AbstractFunctionality 
{ 
    public void Method() 
    { 
     Console.WriteLine("Concrete stuff" + "\n"); 
    } 
} 

... nie jesteś przesłanianie istniejącą metody. Tworzysz nowy,, który ukrywa istniejący. (Powinieneś również otrzymać ostrzeżenie sugerujące użycie modyfikatora new, jeśli naprawdę chcesz tego zachowania.) Interfejs został zaimplementowany w AbstractFunctionality, więc tabela odwzorowania interfejsu odwołuje się do metody w tej klasie.

Teraz jeśli ty reimplement interfejs:

public class ConcreteFunctionality : AbstractFunctionality, IFunctionality 

... to odwzorowanie interfejs będzie odnosić się do sposobu w ConcreteFunctionality a dostaniesz zachowanie można oczekiwać na wezwanie poprzez interfejs (tjTwój trzeci telefon), ale nadal otrzymasz implementację pod numerem AbstractFunctionality dla twojego drugiego połączenia.

Zasadniczo byłoby czystsze i bezpieczniejsze zachowanie metody wirtualnej w trybie AbstractFunctionality i zastąpienie jej w ConcreteFunctionality. W ten sposób we wszystkich przypadkach będzie korzystać z implementacji ConcreteFunctionality.

+1

Nie dałoby to oczekiwanych zachowań, ponieważ drugie połączenie byłoby nadal realizowane przez abstrakcyjną implementację. –

+0

@ JonHanna: Nie zauważyłem oczekiwania, że ​​drugie połączenie będzie * również * używać konkretnej wersji. Dokona edycji. –

14

Brakuje słów kluczowych: virtual i override. Bez tego nie otrzymasz funkcji wirtualnych.

Można oznaczyć Method w AbstractFunctionality jako virtual i zaznaczyć Method w ConreteFunctionality jak override. Jak pokazał mihirj.

Podobne kwestie poruszone w - Why are C# interface methods not declared abstract or virtual?

+1

+1 za interesujący link. – phoog

30

trzeba zdefiniować klasy jako:

public abstract class AbstractFunctionality:IFunctionality 
{ 
    public virtual void Method() 
    { 
     Console.WriteLine("Abstract stuff" + "\n"); 
    }  
} 

public class ConreteFunctionality:AbstractFunctionality 
{ 
    public override void Method() 
    { 
     Console.WriteLine("Concrete stuff" + "\n"); 
    } 
} 

Ponieważ nie zostały nadpisane() metoda w ConreteFunctionality, środowisko czasu pracy wykonuje() metoda wiąże się z AbstractFunctionality obiekt, ponieważ nie może tutaj zastosować dynamicznego polimorfizmu. Wprowadzenie virtual i override powoduje, że środowiska wykonawcze wykonują metodę overriden w klasie potomnej.

+2

Dobra odpowiedź; ale wprowadziłbym pojęcie "ukrywanie", które opisuje oryginalny kod OP, i zauważ, że ukrycie metody bez słowa "nowy" powoduje ostrzeżenie kompilatora. – phoog

Powiązane problemy