2009-04-16 19 views
6

Il seguente codice dovrebbe dare un avvertimento?Perché il metodo Static nasconde il mio metodo di istanza?

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { public static void Do() { /*...*/ } /*...*/ } 

Dà:

"Attenzione CS0108:.. 'Bar.Do()' nasconde membro ereditato 'Foo.Do()' Utilizzare la nuova parola chiave se si nasconde è stato destinato"

Se faccio una modifica al codice:

class Foo { public static void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { public void Do() { /*...*/ } /*...*/ } 

ottengo lo stesso avvertimento.

Se apporto la seguente modifica, tuttavia, l'avviso scompare.

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { new public static void Do() { /*...*/ } /*...*/ } 

Permettetemi di fare un ulteriore cambiamento:

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { 
    new public static void Do() 
    { new Bar().Do();/*...*/ } /*...*/ 
} 

Questo non può essere compilato:

"CS0176 Errore: Gli 'Bar.Do()' non è possibile accedere con un'istanza riferimento, qualificarlo con un nome tipo invece. "

Quindi, perdo l'accesso al metodo ereditato tramite un riferimento di istanza da un metodo statico!

Quale sarebbe la logica dietro? O ho fatto un refuso da qualche parte?

Mi sono imbattuto in questo quando stavo cercando di definire un metodo statico 'Mostra' per il mio modulo derivato da 'Form'.

risposta

5

Dove pensi che sia l'errore? Il fatto che ci sia un avvertimento è assolutamente giusto. Dal spec C# 3.0, sezione 10.3.4:

Una classe-membro-dichiarazione è consentito di dichiarare un membro con lo stesso nome o firma come ereditato membro.Quando si verifica ciò, si dice che il membro di classe derivato nasconda il membro di classe di base. Nascondere un membro ereditato non è considerato un errore, ma fa sì che il compilatore emetta un avviso . Per sopprimere l'avviso, la dichiarazione della classe derivata può includere un nuovo modificatore su indicare che il membro derivato è destinato a nascondere il membro di base.

Il fatto che il metodo di invocazione non è più sottile, ma è fondamentalmente perché l'algoritmo di ricerca membro sceglie il metodo statico, e quindi viene utilizzata questa parte della sezione 7.5.5.1:

validazione finale del il metodo migliore scelto viene eseguita:

il metodo è convalidato nel contesto del gruppo metodo : Se il metodo migliore è un metodo statico , il gruppo metodo deve avere derivava da un nome semplice o da un accesso membro attraverso un tipo. Se il metodo migliore è un metodo di istanza, il gruppo di metodi deve essere il risultato di un nome semplice , un accesso membro tramite una variabile o un valore o un accesso di base. Se nessuno di questi requisiti è true, si verifica un errore in fase di compilazione.

+0

Ciao Jon, +1 per la risposta. Penso che, dal punto di vista dell'utente della lingua, il bug sia nel modo di scegliere il metodo migliore per chiamare :-). Per me, "new Bar(). Do()" indica chiaramente quale metodo viene chiamato in fase di compilazione e non è necessario produrre errori! – isntn

+1

Sospetto che l'alternativa sia quella di rendere il linguaggio molto più complicato. Ci sono spesso casi limite che potrebbero essere migliorati se la lingua fosse più intelligente - ma sarebbe più difficile "conoscere" bene la lingua e anche implementarla correttamente in un compilatore. È tutto equilibrio ... –

2

No, questo ha perfettamente senso. Questo funziona come previsto:

using System; 
using System.Collections.Generic; 

class Foo { public void Do() { /*...*/ } /*...*/ } 
class Bar : Foo { 
    new public static void Do() 
    { ((Foo)new Bar()).Do();/*...*/ } /*...*/ 
} 

Questo perché il compilatore presuppone che si dispone di un tipo di bar, e poi trova il membro statico. Lasciandolo su Foo (che viene fornito gratuitamente), lo fai apparire nei metadati di Foo() e tutto va bene.

+0

quando dico. "New Bar() Do();". Sto sicuramente chiamando il metodo di istanza "Do", che è disponibile in Bar via Foo. Quindi, perché dobbiamo digitare il cast? – isntn

+1

Poiché il compilatore non esamina l'istanza, ma i metadati del tipo. E qui trova solo un metodo con la firma corretta (nome e lista di argomenti vuota), ed è quella statica. – Lucero

+0

Pensaci in termini di tabelle di fuction virtuali; la mappatura Bar :: Do() nasconde la mappatura di Foo: Do ​​(). –

2

Prova questo:

 new public static void Do() 
     { 
      ((Foo)new Bar()).Do(); 
     } 
0

Nel tuo esempio di codice finale, la nuova parola chiave sulla dichiarazione di Bar.Do() significa che si intende nascondere Foo.Do().

0

Per curiosità, perché vuoi farlo? Sembra che probabilmente stai seguendo la tua soluzione nel modo sbagliato.

Il codice sopra sembra funzionare come dovrebbe e i messaggi del compilatore indicano quali sono i problemi.

+0

Ciao Josh, non voglio "volerlo" farlo. È solo che mi imbatto in questo, e voglio capire questo comportamento scelto dai progettisti C#. "new Bar(). Do()" indica ovviamente che si sta chiamando il metodo di istanza. Quindi, perché C# è progettato per renderlo ancora più esplicito? un po 'di domanda educativa. – isntn

+0

Capisco. Bene, in quel caso, devi rendertene conto che in Bar, c'è un metodo di istanza * no * chiamato Do(), solo un metodo statico. Dandogli lo stesso nome, hai bloccato l'ereditarietà. Quindi no, non è ovvio che il metodo di istanza sia chiamato, per me o il compilatore = p – JoshJordan

+0

Penso, ci sia un metodo di istanza in Bar che è derivato da Foo. – isntn

1

si dovrebbe essere in grado di chiamare facendo chiamando base.Do() invece di Bar() Do()

Problemi correlati