2010-01-22 6 views
5

Potrei avere qualcosa di simile:Utilizzando metodi generici, è possibile recuperare diversi tipi dallo stesso metodo?

int x = MyMethod<int>(); 
string y = MyMethod<string>(); 

Così, un metodo che restituisce diversi tipi basati su T. Naturalmente, ci sarebbe la logica all'interno del metodo per assicurarsi che stava tornando la cosa giusta.

Non riesco mai a ottenere qualcosa di simile per l'esecuzione. Si lamenta che non può lanciare il valore di ritorno a T:

public static T MyMethod<T>() 
{ 
    if(typeof(T) == typeof(Int32)) 
    { 
    return 0; 
    } 
    else 
    { 
    return "nothing"; 
    } 
} 
+4

F prima di tutto, questo codice non verrà compilato, poiché non è specificato alcun tipo di reso. Sto assumendo che tu voglia leggere 'public static T MyMethod – Nick

+0

Post come risposta, Nick. Penso che sia la soluzione di cui ha bisogno. – JMD

+0

... anche se quel codice come scritto sopra non verrà compilato, perché "niente" non è T, tranne quando T è una stringa e 0 non è T, tranne quando T è un tipo numerico. – JMD

risposta

10

provare il seguente

public static T MyMethod<T>() { 
    if (typeof(T) == typeof(Int32)) { 
    return (T)(object)0; 
    } else { 
    return (T)(object)"nothing"; 
    } 
} 

Il trucco è il casting per object. Quello che stai cercando di fare è intrinsecamente pericoloso poiché il compilatore non può dedurre che 0 o "niente" sono convertibili in alcun dato T. Dopo tutto, è illimitato. Quindi, spiega esplicitamente al compilatore che non è sicuro con il casting su object.

+0

Questo funziona. Quindi, l'unico pensiero che stavi facendo in modo diverso è di lanciarlo prima su un oggetto, poi su T? – Deane

+1

Mentre questo risolve l'errore del tempo di compilazione, ma ancora non ha senso. Se T è, per esempio, un tipo di pagina, non ha senso restituire una stringa cast a T tramite questo hack (oggetto). L'unica ragione per la quale viene compilato è che sia le stringhe che i numeri interi possono essere convertiti in oggetto e gli oggetti possono essere convertiti in maiuscoli e minuscoli (ad esempio, tutto). –

0

Si potrebbe fare, se si desidera un valore di tipo "nullo" restituito se non è un int. Ma se vuoi una stringa in tutti gli altri casi, controlla le altre risposte.

public static T MyMethod<T>() 
{ 
    if(typeof(T) == typeof(Int32)) 
    { 
    return (T)(object)0; 
    } 
    else 
    { 
    return default(T); // or null 
    } 
} 
+0

Per l'esempio di stringa, l'OP vuole che restituisca un valore stringa specifico, non predefinito (T). Ti manca anche un tipo di reso. – JaredPar

+0

Vero .. e mi manca perché ho copiato il codice e ho perso quella parte prima della modifica. –

+0

Questo non funzionerà - non c'è conversione tra int e T – Lee

0

@Nick è corretto nel suo commento che il tuo codice non verrà compilato. Ma supponendo che cercavi:

public static T MyMethod<T>() 
{ 
    if(typeof(T) == typeof(Int32)) 
    { 
    return 0; 
    } 
    else 
    { 
    return "nothing"; 
    } 
} 

Si può essere difficile per rendere i farmaci generici non generico come si sta tentando (e in realtà in contrasto con il punto intero), ma questo dovrebbe funzionare:

public static T MyMethod<T>() 
{ 
    if(typeof(T) == typeof(Int32)) 
    { 
    return (T)(object)0; 
    } 
    else if(typeof(T) == typeof(string)) 
    { 
    return (T)(object)"nothing"; 
    } 

    return default(T); 
} 
+0

Sì, era la stessa soluzione di cui sopra. Suppongo di dover prima eseguire il cast su un oggetto, dal momento che non c'è un cast diretto da int a T. Ma c'è un cast da int a object e object to T. È corretto? – Deane

+0

Perché si seleziona typeof (T) yes. In realtà la clausola else dovrebbe controllare typeof (stringa) altrimenti qualcosa come MyMethod fallirebbe. Modifico l'esempio – dkackman

0

Questo isn' t valido in quanto non vi è alcuna garanzia che T sia calcinabile/convertibile in stringa o int.

I generici NON sono varianti, vale a dire tipi che possono contenere qualsiasi cosa - sono in fase di compilazione risolti in un tipo reale. Il tuo codice non viene compilato perché non dovrebbe. Puoi aggirare i problemi relativi alla compilazione utilizzando alcuni degli hack pubblicati qui, ma questo è davvero un problema logico. Fai un passo indietro e ripensa a ciò che stai cercando di fare invece di cercare di aggirare il compilatore.

+0

Posso in qualche modo vincolare T a essere solo stringa o int? – Deane

+0

@Deane - non si può – dkackman

+0

@Deane - in VB o similari lingue script, è possibile restituire tutto quello che vuoi da una funzione - int, string, float, pagina di riferimento webservice, quello che hai. Nei linguaggi fortemente tipizzati, non è così, perché il compilatore si aspetta che tu prenda il controllo degli stati e non lasci che faccia il tuo lavoro per te. Che aspetto ha il CODICE DI CHIAMATA che ti serve questo tipo di risultato ?! –

1

Leggermente fuori tema, ma se si sta cercando di fare questa cosa, allora può essere che il vostro disegno è sbagliato ...

Perché non sovraccaricare il metodo e impostare il risultato come un paramter out:

void MyMethod(out int result) 
{ 
    result=0; 
} 

void MyMethod(out string result) 
{ 
    result="my value"; 
} 

allora si può dire:

int value; 
MyMethod(out value); 

E il compilatore selezionare la versione giusta

+0

Non è un uso corretto dei generici essere in grado di usare la stessa logica per diversi tipi? Ho solo un metodo che ha un po 'di logica, ma in diverse situazioni, ho bisogno di tipi diversi da esso. Non è questo il modo giusto di usare i farmaci generici? – Deane

+0

Ma stai attivando il tipo, il che causerà un problema ... Pubblicherò un'alternativa – Sean

+0

Sì, funzionerebbe. Semplicemente, sembra meno aggraziato, perché ora ho tre metodi: uno per ciascun tipo e uno per la logica principale. Perché l'attivazione del tipo comporta un problema? – Deane