2009-07-28 17 views
14

Qualcuno può spiegare l'effettivo utilizzo del metodo nascondendo in C# con un esempio valido?nascosto in C# con un esempio valido. perché è implementato nel framework? qual è il vantaggio del mondo reale?

Se il metodo viene definito utilizzando la parola chiave new nella classe derivata, non può essere sovrascritto. Quindi equivale a creare un metodo nuovo (diverso da quello menzionato nella classe base) con un nome diverso.

C'è qualche motivo specifico per utilizzare la parola chiave new?

+2

Cosa intendi con "esempio valido"? Un esempio che è semplicemente sintatticamente corretto o un esempio che mostra le migliori pratiche per nascondere il metodo? –

risposta

7

C# non solo supporta la sovrascrittura del metodo, ma anche il metodo di occultamento. In poche parole, se un metodo non sta ignorando il metodo derivato, lo sta nascondendo. Un metodo di nascondimento deve essere dichiarato usando la nuova parola chiave. La definizione di classe corretto nel secondo elenco è così:

using System; 
    namespace Polymorphism 
    { 
     class A 
     { 
      public void Foo() { Console.WriteLine("A::Foo()"); } 
     } 

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

     class Test 
     { 
      static void Main(string[] args) 
      { 
       A a; 
       B b; 

       a = new A(); 
       b = new B(); 
       a.Foo(); // output --> "A::Foo()" 
       b.Foo(); // output --> "B::Foo()" 

       a = new B(); 
       a.Foo(); // output --> "A::Foo()" 
      } 
     } 
    } 
+1

Immagino che lo stesso si possa ottenere senza la nuova parola chiave, solo che il compilatore dà un avvertimento. altrimenti ha qualche differenza significativa? – vijaysylvester

+0

no, non c'è nessuna differenza, compilatore dà un avvertimento e funziona come hai scritto nuova parola chiave se non si presta attenzione a avvertimento –

+0

La cosa importante è che il tipo di riferimento determina il metodo chiamato. –

10

Un uso io a volte ho per la nuova parola chiave è per 'poveri covarianza proprietà mans' in un albero di ereditarietà parallell. Considerate questo esempio:

public interface IDependency 
{ 
} 

public interface ConcreteDependency1 : IDependency 
{ 
} 

public class Base 
{ 
    protected Base(IDependency dependency) 
    { 
    MyDependency = dependency; 
    } 

    protected IDependency MyDependency {get; private set;} 
} 

public class Derived1 : Base // Derived1 depends on ConcreteDependency1 
{ 
    public Derived1(ConcreteDependency1 dependency) : base(dependency) {} 

    // the new keyword allows to define a property in the derived class 
    // that casts the base type to the correct concrete type 
    private new ConcreteDependency1 MyDependency {get {return (ConcreteDependency1)base.MyDependency;}} 
} 

l'albero di ereditarietà Derived1: Base ha una 'dipendenza parallell' sul ConcreteDependency1: IDependency'. Nella classe derivata, so che MyDependency è di tipo ConcreteDependency1, quindi posso nascondere il getter della proprietà dalla classe base usando la nuova parola chiave.

MODIFICA: vedere anche this blog post by Eric Lippert per una buona spiegazione della nuova parola chiave.

+3

interessante -> +1 – Juri

+0

Quello era davvero un bravo ragazzo. non ero a conoscenza di queste complessità – vijaysylvester

+0

concordato, +1 per esempio informativo e utile. – shambulator

7

Penso che l'esempio di ArsenMkrt non sia completamente corretto, almeno non spiega completamente la funzione di occultamento. Facendo cadere la nuova parola chiave dal metodo Foo in classe B, si continua a ottenere l'output

A::Foo() 
B::Foo() 
A::Foo() 

In un linguaggio di programmazione come Java, dove tutti i metodi sono "virtuali", che ci si aspetta di ottenere l'output

A::Foo() 
B::Foo() 
B::Foo() 

prendendo il codice di ArsenMkrt sopra, a causa l'istanza

A a; 
B b; 

a = new A(); 
b = new B(); 
a.Foo(); 
b.Foo(); 

a = new B(); //<< Here 
a.Foo(); 

nel suo esempio tuttavia, è ancora ottenere "a :: Foo()", perché in C# metodi non sono virtuali di default e S o il metodo B :: Foo() nasconde automaticamente A's Foo(). Per ottenere il comportamento polimorfico si deve scrivere come segue invece:.

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

class B : A 
{ 
    public override void Foo() { Console.WriteLine("B::Foo()"); } 
} 

Ora è dove la "nuova" parola chiave viene in realtà quando si lascia il "override" da B :: Foo(), allora si di nuovo nasconderebbe A :: Foo() che significa che non si ignora il comportamento predefinito e non si ottiene il polimorfismo, cioè si ottiene "A :: Foo()" di nuovo come output. Lo stesso può essere raggiunto - ed ecco dove non riesco a capire al 100% perché lo si debba mettere - inserendo la parola chiave "nuova" come ..

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

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

e ancora ottenere l'uscita

A::Foo() 
B::Foo() 
A::Foo() 
+2

domanda è mercato C# come si vede –

+4

Juri evidenzia una differenza con Java, ma lui sta parlando di C# ... – jeroenh

1

Uno scenario un po 'oscuro, dove il metodo nascondiglio sarebbe opportuno, ma per la mancanza di qualsiasi modo pulito idiomatica di esprimerla, è in circostanze in cui una base la classe espone un membro protetto a un discendente ereditabile, ma quel discendente sa che non c'è modo che altre classi derivate possano usare quel membro senza rompere le cose. Un primo esempio di un metodo che molte classi dovrebbero nascondere (ma molto poche) è MemberwiseClone(). In molti casi, se una classe ha un membro private che si aspetta sia l'unico riferimento esistente a un oggetto mutabile, non esiste alcun mezzo con cui una classe derivata possa mai utilizzare correttamente MemberwiseClone().

noti che nascondere membri protetti non non costituiscono una violazione del LSP. La conformità con LSP richiede che nei luoghi in cui il codice possa essere in attesa di un riferimento a un oggetto di classe base ma riceva un riferimento a un oggetto di classe derivata, quest'ultimo dovrebbe funzionare come lo sarebbe quello di classe base. I membri protetti, tuttavia, non rientrano nell'ambito dell'SPL, poiché ogni tipo conosce assolutamente il suo tipo di base. Se Bar e Boz entrambi derivano da Foo, e Boz nasconde un membro protetto che richiede Bar, il fatto che Boz nasconde il membro non influirà Bar, perché Bar s' esempio base-tipo non può assolutamente essere un qualcosa di Boz o altro di Foo. Nessuna sostituzione è possibile, e quindi la sostituibilità è irrilevante.

+0

penso sia meglio aggiungere alcune righe di codice alla tua risposta. Mi spiace, è meglio;) – siamak

0

Questo potrebbe aiutare.

class Base 
{ 
    public void F() {} 
} 
class Derived: Base 
{ 
    public void F() {}  // Warning, hiding an inherited name 
} 

Nell'esempio precedente, la dichiarazione di F in Derivato causa la segnalazione di un avviso. Nascondere un nome ereditato non è specificamente un errore, poiché ciò preclude l'evoluzione separata delle classi base. Ad esempio, la situazione descritta sopra potrebbe essere dovuta al fatto che una versione successiva di Base ha introdotto un metodo F che non era presente in una versione precedente della classe. Se la situazione precedente fosse stata un errore, qualsiasi modifica apportata a una classe base in una libreria di classi con versione separata potrebbe potenzialmente rendere le classi derivate non valide. Fonte: https://msdn.microsoft.com/en-us/library/aa691135%28v=vs.71%29.aspx

0

Una volta quando li userete è quando è necessario aggiungere/modificare un attributo che si trova su un metodo di classe base. Per esempio:

[Browsable(true)] 
[EditorBrowsable(EditorBrowsableState.Always)] 
public new event EventHandler TextChanged 
{ 
    add { base.TextChanged += value; } 
    remove { base.TextChanged -= value; } 
} 

La base Control classe ha un evento TextChanged, ma l'evento di base ha tutti i tipi di attributi schiaffeggiato su di esso per evitare che mostrando in intellisense e il progettista. Poiché la classe che ho usato fa ampio uso sia della proprietà Text sia dell'evento TextChanged, volevo che l'evento TextChanged si visualizzasse in intellisense e fosse visibile nella finestra delle proprietà.

Problemi correlati