2009-04-05 13 views
30

Dire che ho due versioni di overload di un metodo di C#:C#: passaggio da null a overloaded metodo - quale metodo viene chiamato?

void Method(TypeA a) { } 
void Method(TypeB b) { } 

chiamo il metodo con:

Method(null); 

Quale overload del metodo si chiama? Cosa posso fare per garantire che venga chiamato un particolare sovraccarico?

+0

Un altro uno di essere a conoscenza di sovraccarico metodi in cui almeno un metodo utilizza la parola chiave params. –

risposta

67

Dipende da TypeA e TypeB.

  • Se esattamente uno di loro è applicabile (ad esempio non v'è alcuna conversione da null a TypeB perché è un tipo di valore ma TypeA è un tipo di riferimento), la chiamata verrà effettuata a quella applicabile.
  • In caso contrario, dipende dalla relazione tra TypeA e TypeB.
    • Se v'è una conversione implicita TypeA-TypeB ma nessuna conversione implicita TypeB-TypeA allora verrà utilizzato il sovraccarico utilizzando TypeA.
    • Se è presente una conversione implicita da TypeB a TypeA ma nessuna conversione implicita da TypeA a TypeB, verrà utilizzato il sovraccarico utilizzando TypeB.
    • In caso contrario, la chiamata è ambigua e non verrà compilata.

Vedere la sezione 7.4.3.4 delle specifiche C# 3.0 per le modalità.

Ecco un esempio di ciò che non è ambiguo. Qui TypeB deriva da TypeA, il che significa che c'è una conversione implicita da TypeB a TypeA, ma non viceversa. Così il sovraccarico utilizzando TypeB viene utilizzato:

using System; 

class TypeA {} 
class TypeB : TypeA {} 

class Program 
{ 
    static void Foo(TypeA x) 
    { 
     Console.WriteLine("Foo(TypeA)"); 
    } 

    static void Foo(TypeB x) 
    { 
     Console.WriteLine("Foo(TypeB)"); 
    } 

    static void Main() 
    { 
     Foo(null); // Prints Foo(TypeB) 
    } 
} 

In generale, anche a fronte di una chiamata altrimenti ambiguo, per garantire che un particolare sovraccarico viene utilizzato, appena lanciato:

Foo((TypeA) null); 

o

Foo((TypeB) null); 

Si noti che se ciò implica l'ereditarietà nelle classi di dichiarazione (ovvero una classe sta sovraccaricando un metodo dichiarato dalla sua classe base) si è in un altro problema, e si ed a lanciare l'obiettivo del metodo piuttosto che l'argomento.

+0

@Jon: Perché il comportamento come si descrive nel caso è disponibile una conversione implicita? Preferirei aspettarmi il contrario. È solo una questione di definizione? –

+2

@divo: È sicuramente una decisione di progettazione, ma probabilmente la ragione è che il metodo TypeB è praticamente un caso specializzato di metodo TypeA. Voglio dire, per ogni argomento valido, per default il TypeA verrà abbinato a meno che l'oggetto non sia noto come TypeB. Questo comportamento per null garantisce questa coerenza. –

+0

Mehrdad ha ragione: se riesci a convertire da TypeB a TypeA, TypeB è più specifico di TypeA, quindi verrà scelto di preferenza. –

1

chiamata ambigua. (errore di compilazione del tempo).

+0

hi, Ho provato il seguente esempio e non ho ottenuto l'errore di compilazione; qualche pensiero perché? classe Programma { void test1 (ICollection a) { Console.WriteLine ("test1-ICollection"); } void test1 (IList a) { Console.WriteLine ("test1-List"); } vuoto statico Principale (stringa [] args) { Programma p = nuovo Programma(); p.test1 (null); Console.ReadKey(); }} –

+0

ma ho ottenuto la compilazione di errore quando ho cambiato uno dei sovraccarichi di accettare un parametro di tipo IComparer classe Programma { vuoto test1 (IList a) { Console.WriteLine ("test1- Elenco"); } void test1 (IComparer a) { Console.WriteLine ("test1-IComparer"); } vuoto statico Principale (stringa [] args) { Programma p = nuovo Programma(); p.test1 (null); Console.ReadKey(); } } –

8

Jon Skeet ha fornito una risposta esaustiva, ma dal punto di vista del design non si deve dipendere dai casi d'angolo delle specifiche del compilatore. Se non altro, se devi cercare ciò che fa prima di scriverlo, la prossima persona a cercare di leggerla non saprà nemmeno cosa fa. Non è mantenibile

I sovraccarichi ci sono per comodità, e due diversi sovraccarichi con lo stesso nome dovrebbero fare la stessa cosa. Se i due metodi fanno cose diverse, rinomina uno o entrambi.

È più normale per un metodo sovraccarico avere varianti con numeri variabili di parametri e per il sovraccarico con meno parametri per fornire valori predefiniti sensibili.

ad es. string ToString(string format, System.IFormatProvider provider) ha il maggior numero di parametri,
string ToString(System.IFormatProvider provider) fornisce un formato di default, e
string ToString() fornisce un formato predefinito e fornitore,

+0

Non vedo il tuo punto sui sovraccarichi. È vero, i sovraccarichi dovrebbero fare la stessa cosa, ma possono farlo in modi diversi. Ecco perché vuoi sovraccarichi. Il numero di argomenti è irrilevante e potrebbe essere lo stesso o diverso (caso esemplare: i vari metodi di conversione). Informazioni sugli spesificatori del compilatore: a seconda del livello di abilità della persona successiva, qualsiasi cosa può essere un «caso d'angolo». Finché il tuo design ha senso, e funziona in modo intuitivo, fa il suo lavoro. Ciò potrebbe richiedere un'attenta considerazione in fase di progettazione, non tanto quando la classe verrà utilizzata in seguito. –

+0

Penso che il punto che sta facendo è che l'uso più comune di sovraccarichi è quello di eseguire una funzione sui dati che possono includere diversi tipi o possono includere più o meno parametri. In effetti, ho scritto una manciata di sovraccarichi in cui quello con meno parametri in realtà ha tutti gli stessi dati (stringhe) in meno pezzi disparati. In tal caso chiamano il sovraccarico più alto dopo aver rotto i pezzi e averli nuovamente forniti. –

0

Una soluzione semplice è quello di creare un altro metodo con la firma di:

void Method() { } 

o meglio aggiornare la firma su uno dei metodi di essere:

void Method(TypeB b = null) { } 

e quindi chiamare i t come così:

Method(); 

Al momento della compilazione del valore null è tipizzato e quindi il compilatore non può corrispondere con una delle firme del metodo. In fase di esecuzione, qualsiasi variabile che potrebbe essere risolta in null verrà comunque digitata e pertanto non causerà alcun problema.

3

Jon Skeet ha già risposto a quale sovraccarico viene scelto per impostazione predefinita, ma se si desidera garantire che venga richiamato un particolare overload, è spesso preferibile utilizzare parametri denominati rispetto al cast.

Se si dispone di:

void Method(TypeA a) { } 
void Method(TypeB b) { } 

è possibile chiamare o Method(a: null);Method(b: null);

Problemi correlati