2013-02-26 15 views
9

Così, mi sono imbattuto in una risposta da Servy (https://stackoverflow.com/a/15098242/496680) e un po 'del suo codice fa questo:tipo generico Quali sono implicite Parametri

public static int BinarySearch<TSource, TKey>(...) 

per un metodo di estensione, ma chiama in questo modo:

arr.BinarySearch(...) 

Ho chiesto in giro e qualcuno ha rilevato che è un parametro di tipo generico implicito. Ho cercato su Google ma non ho trovato alcuna informazione su di essi. Capisco come funzionano i farmaci generici, ma non riesco a capire come/quando usarli.

  1. Perché servy li usa nel suo metodo di estensione?
  2. C'è un nome più ufficiale per questi che posso cercare?
+2

Posso rispondere n. 1 in modo sufficiente. Permette al metodo di lavorare con qualsiasi tipo di raccolta, piuttosto che lavorare solo per stringhe o int, o Foos o altro. Ti permette anche di confrontarti con qualsiasi tipo di valore, lascia che sia int o una stringa o una barra o [...]. Nel tuo caso specifico hai solo bisogno di selezionare un 'int' da un array di qualche tipo (che non conoscevo nemmeno come si chiamasse mind you). Usando i generici, funzionerà non solo per il tuo caso, ma per qualsiasi caso simile che abbia lo stesso problema ma con tipi diversi. Questo sarà più utile per i futuri visitatori che trovano la tua domanda. – Servy

+0

@Servy ringraziamenti! Per i futuri lettori ho trovato anche questo post: http://stackoverflow.com/questions/4885027/how-does-generic-type-inference-work-in-c –

risposta

10

Bene, hai tralasciato la parte più importante che fa funzionare tutto. I parametri di tipo possono essere dedotte dai parametri degli oggetti reali passati in

Ad esempio:.

static class Extensions { 
    internal static IEnumerable<U> Test<T, U>(
            this IEnumerable<T> items, 
            Func<T, U> converter) { 
    foreach (T item in items) { 
     yield return converter(item); 
    } 
    } 
} 

Questa estensione metodo funziona su qualsiasi classe IEnumerable e convertirà ogni elemento nell'enumerazione un altro tipo basato sul convertitore che hai fornito. Questo è generici standard.

ora, ci sono molti modi per chiamare questo metodo:

IEnumerable<int> values = Enumerable.Range<int>(1, 10); 
Func<int, string> converter = i => i.ToString("0.00"); 

// Variation 1, explicit calling 
IEnumerable<string> results1 = Extensions.Test<int, string>(values, converter); 

// Variation 2, explicit calling with type inference 
IEnumerable<string> results2 = Extensions.Test(values, converter); 

// Variation 3, extension method calling, still providing explicit types 
IEnumerable<string> results3 = values.Test<int, string>(converter); 

// Variation 4, extension method with type inference 
IEnumerable<string> results4 = values.Test(converter); 

Tutti e quattro variazioni chiamano lo stesso metodo e restituiscono lo stesso risultato. L'inferenza di tipo funziona osservando i parametri passati e inferendo automaticamente i loro tipi in base a ciò che viene fornito. Nei nostri esempi sopra, è in grado di determinare che il tipo è di tipo int perché abbiamo passato in un IEnumerable<int> nel parametro per IEnumerable<T>. È anche in grado di dedurre che il tipo U è di tipo string perché abbiamo trasmesso un Func corrispondente al tipo iniziale di T con int e restituendo una stringa. Quindi lo Func<T, U> è compilato con la nostra funzione di convertitore di Func<int, string>.

Dall'inferenza sopra, è un metodo generico standard a quel punto. Digitare i metodi di inferenza e di estensione non sono altro che convenienza/zucchero sintattico.Infatti, se decompilate l'output, potete vedere che i metodi di estensione sono sostituiti con chiamate statiche e di solito sono definiti con i parametri di tipo esplicitamente compilati. (Questo varia in base al decompilatore e alle opzioni impostate).

+0

Per gli ultimi due esempi è necessario omettere 'values' come parametro. – Servy

+0

Oops, grazie! È incredibile quello che puoi perdere quando non puoi compilare! – Joshua

+0

Ottima spiegazione! Grazie! –

2

Il termine che di solito ascolto è "tipo di inferenza".

+0

Sì, si chiama "tipo di inferenza". C'è un esempio di base in [Metodi generici (C# Programming Guide)] (http://msdn.microsoft.com/en-us/library/twcad0zb.aspx) dove si dice: _Puoi anche omettere l'argomento type e il compilatore ** lo inferirà **. La seguente chiamata a Swap è equivalente alla chiamata precedente: [...] Le stesse regole per l'inferenza di tipo si applicano ai metodi statici e ai metodi di istanza. Il compilatore può inferire i parametri del tipo in base agli argomenti del metodo che si passano; non può inferire i parametri del tipo solo da un vincolo o da un valore di ritorno. [...] _ –

6
  1. usa una generic method in questo caso perché permette il suo metodo di lavorare con qualsiasi tipo di contenuto all'interno di un Collection<T>. Il metodo generico rende questo molto flessibile e utilizzabile per qualsiasi tipo. Usa il tipo inferenza quando chiama il metodo perché semplifica il codice nel sito di chiamata.

  2. La gestione automatica è denominata Tipo Inferrence ed è descritta dettagliatamente nella specifica del linguaggio C#, sezione 7.5.2: Tipo Inferrence. Se vuoi capirlo in dettaglio, ti consiglio di scaricare lo C# language specification.

Problemi correlati