2009-09-09 14 views
134

chiedendo quale sia la differenza tra i seguenti:Differenza tra nuovo e ignorare

Caso 1: Classe Base

public void DoIt(); 

Caso 1: classe ereditata

public new void DoIt(); 

Caso 2: Classe Base

public virtual void DoIt(); 

Caso 2: classe ereditata

public override void DoIt(); 

entrambi i casi 1 e 2 sembrano avere lo stesso effetto sulla base dei test che ho eseguito. C'è una differenza o un modo preferito?

+2

duplicato di molte questioni, tra cui http://stackoverflow.com/questions/159978/c-keyword-usage-virtualoverride-vs-new –

risposta

170

Il modificatore override può essere utilizzato su metodi virtuali e deve essere utilizzato su metodi astratti. Questo indica per il compilatore per utilizzare l'ultima implementazione definita di di un metodo. Anche se il metodo viene chiamato su un riferimento a , la classe base utilizzerà l'implementazione sovrascrivendola.

public class Base 
{ 
    public virtual void DoIt() 
    { 
    } 
} 

public class Derived : Base 
{ 
    public override void DoIt() 
    { 
    } 
} 

Base b = new Derived(); 
b.DoIt();      // Calls Derived.DoIt 

chiamerà Derived.DoIt se che sostituisce Base.DoIt.

Il nuovo modificatore indica al compilatore di utilizzare l'implementazione classe figlia invece della classe genitore implementazione. Qualsiasi codice che non sia facendo riferimento alla classe ma la classe madre utilizzerà l'implementazione della classe genitore .

public class Base 
{ 
    public virtual void DoIt() 
    { 
    } 
} 

public class Derived : Base 
{ 
    public new void DoIt() 
    { 
    } 
} 

Base b = new Derived(); 
Derived d = new Derived(); 

b.DoIt();      // Calls Base.DoIt 
d.DoIt();      // Calls Derived.DoIt 

chiamerà prima Base.DoIt, quindi Derived.DoIt. Sono effettivamente due metodi completamente separati che hanno lo stesso nome, piuttosto che il metodo derivato che sostituisce il metodo base.

Fonte: Microsoft blog

+4

'Questo indica per il compilatore di utilizzare l'ultimo definito implementazione di un method'. come si può trovare l'ultima implementazione definita di un metodo ?? – AminM

+5

Inizia da una classe concreta, controlla se ha un'implementazione del metodo di interesse. Se lo fa, hai finito. In caso contrario, fare un passo avanti nella gerarchia dell'ereditarietà, ovvero verificare se la super classe ha il metodo di interesse. Continua fino a quando non hai trovato il metodo di interesse. – csoltenborn

7

prova seguente: (case1)

((BaseClass)(new InheritedClass())).DoIt() 

Edit: + Override virtuale sono risolti in fase di esecuzione (in modo da ignorare davvero sovrascrive metodi virtuali), mentre il nuovo basta creare nuovo metodo con lo stesso nome, e nasconde il vecchio , viene risolto in fase di compilazione -> il tuo compilatore chiamerà il metodo che "vede"

13

Nel primo caso si nasconde la definizione nella classe genitore. Ciò significa che sarà invocato solo quando si ha a che fare con l'oggetto come classe figlio. Se lanci la classe sul suo tipo genitore, verrà invocato il metodo genitore. Nella seconda istanza, il metodo viene sottoposto a override e verrà invocato indipendentemente dal fatto che l'oggetto sia cast come classe child o genitore.

149

virtuale: indica che un metodo può essere sovrascritto da un inheritor

Override: prevale la funzionalità di un metodo virtuale in una classe base, fornendo funzionalità diverse.

nuovi: pelli il metodo originale (che non deve essere virtuale), che fornisce funzionalità diverse. Questo dovrebbe essere usato solo dove è assolutamente necessario.

Quando si nasconde un metodo, è ancora possibile accedere al metodo originale sostituendolo alla classe base. Questo è utile in alcuni scenari, ma pericoloso.

+0

Perché è attivo un metodo che nasconde il metodo di base pericoloso? O stai insinuando che il casting in generale è pericoloso? – Mark

+1

@Mark: un chiamante potrebbe non essere a conoscenza dell'implementazione, causando un uso improprio accidentale. –

3

La differenza tra i due casi è che nel caso 1, il metodo base DoIt non viene sovrascritto, solo nascosto. Ciò significa che, a seconda del tipo di variabile, dipende da quale metodo verrà chiamato. Ad esempio:

BaseClass instance1 = new SubClass(); 
instance1.DoIt(); // Calls base class DoIt method 

SubClass instance2 = new SubClass(); 
instance2.DoIt(); // Calls sub class DoIt method 

Questo può essere davvero confuso e comporta un comportamento non previsto e dovrebbe essere evitato se possibile. Quindi il modo preferito sarebbe il caso 2.

3

Nel caso 1, se si è utilizzato il metodo DoIt() della classe ereditata mentre il tipo è dichiarato come classe base, si vedrà anche l'azione della classe base.

/* Results 
Class1 
Base1 
Class2 
Class2 
*/ 
public abstract class Base1 
{ 
    public void DoIt() { Console.WriteLine("Base1"); } 
} 
public class Class1 : Base1 
{ 
    public new void DoIt() { Console.WriteLine("Class1"); } 
} 
public abstract class Base2 
{ 
    public virtual void DoIt() { Console.WriteLine("Base2"); } 
} 
public class Class2 : Base2 
{ 
    public override void DoIt() { Console.WriteLine("Class2"); } 
} 
static void Main(string[] args) 
{ 
    var c1 = new Class1(); 
    c1.DoIt(); 
    ((Base1)c1).DoIt(); 

    var c2 = new Class2(); 
    c2.DoIt(); 
    ((Base2)c2).DoIt(); 
    Console.Read(); 
} 
+0

Dado mostra come token non valido quando provo il tuo codice – Learner

+0

Potresti pubblicare l'avviso o l'errore che stai ricevendo. Questo codice ha funzionato bene quando l'ho pubblicato originariamente. –

+0

Questo dovrebbe essere incollato nella classe del punto di ingresso (Programma). Questo è stato rimosso per consentire una migliore formattazione su questo sito. –

1

Se la parola chiave override viene utilizzato in classe Derive allora il suo override del metodo genitore.

Se la parola chiave new viene utilizzata nella classe derivata, derivare il metodo nascosto dal metodo padre.

0

La differenza funzionale non verrà mostrato in questi test:

BaseClass bc = new BaseClass(); 

bc.DoIt(); 

DerivedClass dc = new DerivedClass(); 

dc.ShowIt(); 

In questo exmample, il Doit che si chiama è quello che ci si aspetta di essere chiamato.

Per vedere la differenza che devi fare questo:

BaseClass obj = new DerivedClass(); 

obj.DoIt(); 

Si vedrà se si esegue quel test che, nel caso 1 (come definito di esso), il DoIt() in BaseClass si chiama, nel caso 2 (come lo hai definito), viene chiamato lo DoIt() in DerivedClass.

0

Ho avuto la stessa domanda ed è davvero confuso, si dovrebbe considerare che esclusione e nuove parole chiave lavorare solo con oggetti di tipo classe base e il valore della classe derivata.In questo caso solo si vedrà l'effetto di sostituzione e nuova: Quindi, se avete class A e B, B eredita da A, allora istanziare un oggetto come questo:

A a = new B(); 

Ora sui metodi di chiamata si terrà il suo stato in considerazione. Override: significa che estende la funzione del metodo, quindi utilizza il metodo nella classe derivata, mentre new indica al compilatore di nascondere il metodo nella classe derivata e utilizza invece il metodo nella classe base. Ecco un ottimo spettacolo da quel soggetto:

https://msdn.microsoft.com/EN-US/library/ms173153%28v=VS.140,d=hv.2%29.aspx?f=255&MSPPError=-2147217396

1

Il mio modo di tenere a mente due parole chiave che sono opposti l'uno dall'altro.

override: virtual la parola chiave deve essere definita per sovrascrivere il metodo. Il metodo che usa la parola chiave override indipendentemente dal tipo di riferimento (riferimento di classe base o classe derivata) se è istanziato con la classe base, il metodo di esecuzione della classe base. Altrimenti, il metodo delle esecuzioni di classi derivate.

new: se la parola chiave viene utilizzata da un metodo, a differenza della parola chiave override, il tipo di riferimento è importante. Se viene creata un'istanza con la classe derivata e il tipo di riferimento è la classe base, viene eseguito il metodo della classe base. Se viene creata un'istanza con la classe derivata e il tipo di riferimento è una classe derivata, viene eseguito il metodo della classe derivata. Vale a dire, è il contrasto della parola chiave override. En passant, se si dimentica o omette di aggiungere una nuova parola chiave al metodo, il compilatore si comporta di default con la parola chiave new.

class A 
{ 
    public string Foo() 
    { 
     return "A"; 
    } 

    public virtual string Test() 
    { 
     return "base test"; 
    } 
} 

class B: A 
{ 
    public new string Foo() 
    { 
     return "B"; 
    } 
} 

class C: B 
{ 
    public string Foo() 
    { 
     return "C"; 
    } 

    public override string Test() { 
     return "derived test"; 
    } 
} 

Chiamata in principale:

A AClass = new B(); 
Console.WriteLine(AClass.Foo()); 
B BClass = new B(); 
Console.WriteLine(BClass.Foo()); 
B BClassWithC = new C(); 
Console.WriteLine(BClassWithC.Foo()); 

Console.WriteLine(AClass.Test()); 
Console.WriteLine(BClassWithC.Test()); 

uscita:

A 
B 
B 
base test 
derived test 
1

L'articolo che segue è in vb.net ma penso che la spiegazione su nuova vs le sostituzioni è molto facile da afferrare.

https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides

Ad un certo punto in questo articolo, c'è questa frase:

In generale, ombre assume la funzione associata con il tipo è invocato, mentre Sostituzioni assume l'implementazione di un oggetto è eseguito.

La risposta accettata a questa domanda è perfetta ma penso che questo articolo fornisca buoni esempi per aggiungere un miglior significato alle differenze tra queste due parole chiave.

-1

Di tutti quelli, nuovo è il più confuso. Attraverso la sperimentazione, la nuova parola chiave è come dare agli sviluppatori la possibilità di sovrascrivere l'implementazione della classe ereditaria con l'implementazione della classe base definendo esplicitamente il tipo. È come pensare al contrario.

Nell'esempio seguente, il risultato restituirà "Risultato derivato" fino a quando il tipo non viene definito esplicitamente come test BaseClass, quindi verrà restituito "Risultato base".

class Program 
{ 
    static void Main(string[] args) 
    { 
     var test = new DerivedClass(); 
     var result = test.DoSomething(); 
    } 
} 

class BaseClass 
{ 
    public virtual string DoSomething() 
    { 
     return "Base result"; 
    } 
} 

class DerivedClass : BaseClass 
{ 
    public new string DoSomething() 
    { 
     return "Derived result"; 
    } 
} 
+0

Aggiungi il tuo commento se obietti. Colpire e scappare è così codardo. – usefulBee

0

Nel primo caso chiamerà il metodo DoIt() della classe derivata perché la nuova parola chiave nasconde il metodo DoIt() della classe base.

Al secondo caso sarà chiamata soprascritta DoIt()

public class A 
{ 
    public virtual void DoIt() 
    { 
     Console.WriteLine("A::DoIt()"); 
    } 
} 

public class B : A 
{ 
    new public void DoIt() 
    { 
     Console.WriteLine("B::DoIt()"); 
    } 
} 

public class C : A 
{ 
    public override void DoIt() 
    { 
     Console.WriteLine("C::DoIt()"); 
    } 
} 

lasciate creare un'istanza di queste classi

A instanceA = new A(); 

    B instanceB = new B(); 
    C instanceC = new C(); 

    instanceA.DoIt(); //A::DoIt() 
    instanceB.DoIt(); //B::DoIt() 
    instanceC.DoIt(); //B::DoIt() 

Tutto è previsto al precedente. Lascia impostare istanzaB e istanzaC su instanceA e chiama il metodo DoIt() e controlla il risultato.

instanceA = instanceB; 
    instanceA.DoIt(); //A::DoIt() calls DoIt method in class A 

    instanceA = instanceC; 
    instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C