L'inferenza di tipo over IEnumerable
-
11-09-2019 - |
Domanda
Ci sono alcuni posti già su Stack Overflow su questo genere di cose, ma non esattamente la stessa - in modo scuse in anticipo se si tratta di qualcosa che è già stato risposto
.Perché questo non funziona:
public class MyBase { }
public class MyUtils
{
public bool Foo<T> (T myObject) { return true; }
public bool Foo (MyBase myBaseObject) { return false; }
public void Go<T> (IEnumerable<T> items)
{
foreach (var item in items)
{
// this test fails
Assert.IsFalse (Foo (item));
}
}
}
Se io chiamo Go () di cui sopra e passare un carico di oggetti MyBase, ogni chiamata a Foo Foo chiamerà la generica (), che restituisce il valore true.
new MyUtils ().Go (new MyBase[] { new MyBase (), new MyBase () });
Perché non chiamare la versione MyBase specializzata invece? Se chiamo Foo (nuova MyBase ()) direttamente, si deduce che correttamente chiamata a fare. È questo a causa della mancanza di covarianza per le collezioni in C # 3, o sono solo di essere stupido e non fare questo correttamente?
Grazie!
Isaac
Soluzione
E non chiama il "specializzata" uno perché il compilatore sceglie il metodo da chiamare quando il programma (che in questo caso, è la funzione Go
) è compilato , non quando viene eseguito.
Quando il compilatore è la compilazione della funzione Go
, l'unica informazione che ha è che ci sia qualche oggetto di tipo T
. Non ha alcuna idea che si può ad un certo punto più avanti nel tempo gli mette a disposizione un oggetto di tipo MyBase
. L'unica opzione che ha è di scegliere il sovraccarico di Foo<T>
, e così si cuoce che per il programma compilato.
Se si desidera un'applicazione di scegliere sovraccarichi in fase di esecuzione, e scegliere il migliore di sovraccarico, cercando in oggetto, mentre l'applicazione è in esecuzione, che si chiama "la spedizione dinamica", e viene utilizzato solo per i linguaggi dinamici come Ruby, Python, PHP, ecc
C # 3 è completamente statico e non supporta questa. Dovreste scrivere un if-statement nel codice per verificare il tipo se si voleva lavorare in questo modo. C # 4 d'altra parte, ha qualche supporto dinamico. Se si stesse scrivendo questo codice in C # 4, si potrebbe dichiarare la funzione 'Go' nel seguente modo:
public void Go<T> (IEnumerable<dynamic> items)
Poi si userebbe la spedizione dinamica a tempo di esecuzione di scegliere quale sovraffaticamento chiama, e avrebbe chiamato il sovraccarico specializzato di prendere MyBase
Altri suggerimenti
Secondo le specifiche C # (7.4.3.2), il metodo non generico è migliore di quella generica, quindi dovrebbe essere selezionato.
Ma, penso che quella generica viene prelevato nel tuo caso, perché è chiamato in un contesto invocazione generica (il "foreach" loop).