2009-06-23 18 views
9

Sto cercando di scrivere un metodo come questo:Conosco il typeof (T) ma il compilatore no. Come risolvere?

public static T Test<T>() 
{ 
    if (typeof(T)==typeof(string)) 
    return "1241"; 

    // do something else 
} 

ma io non riesco a capire come tirare fuori. Voglio restituire valori in base al tipo di T con cui è stato invocato il metodo. Devo restituire stringhe, int, classi personalizzate, elenco, ecc.

L'effettivo caso di utilizzo è un codice di serializzazione personalizzato in cui è essenziale che il codice di deserializzazione conosca il tipo di oggetto che dovrebbe produrre.

Chiarimento: l'esempio di cui sopra dà il seguente errore: Impossibile convertire la stringa di tipo T

La soluzione ideale sarebbe lavorare sui tipi di valore e tipi di riferimento, e non dovrebbe includere un parametro fittizio per la risoluzione di sovraccarico.

Sto iniziando a dubitare se questa soluzione ideale esiste però.

Grazie, Lucas

+0

typeof (T) dovrebbe funzionare. Quale messaggio di errore ha il compilatore? –

risposta

13

Il cast intermedio a object non è l'ideale, ma qualcosa di simile dovrebbe fare il trucco:

public static T Test<T>() 
{ 
    if (typeof(T) == typeof(string)) 
     return (T)(object)"1241"; 

    // do something else 
} 
+0

Ah merda, l'ho appena detto anche io! :) – leppie

6

Devi cast del valore restituito a T, per esempio qualcosa di simile per i tipi di riferimento:

public static T Test<T>() where T : class 
{ 
    if (typeof(T)==typeof(string)) 
    return "1241" as T; 

    return default(T); 
} 
+0

Il compilatore dice: Impossibile convertire il tipo 'stringa' in T –

+0

Spiacente, ho aggiornato l'esempio. Nota la parte "where T: class". – M4N

+0

solo il problema ora è T deve essere una classe, quindi non funzionerà per int, long, ecc. –

5

Attenzione! La soluzione riportata di seguito è non lavoro (verificato utilizzando il compilatore C# Mono gmcs).

Tuttavia, lo deve essere funzionante in base alla lettura dello standard C#, poiché la risoluzione di sovraccarico dovrebbe preferire la versione non generica del metodo quando possibile. La sezione pertinente in ECMA-334 è 25.1.7: "Sovraccarico in classi generiche". Inoltre, Eric Lippert sembra dirlo anche in uno blog posting.

Il feedback sarebbe apprezzato: perché non funziona come previsto?


Hai avuto tipi indipendenti e comportamenti estranei: questo codice urla “! uso sovraccarico

Generics sarebbe opportuno per i tipi non correlati, comportamento eppure uguali (o molto simili).

fare questo (programma completo di test per riprodurre il comportamento):

using System; 

class TestClass { 
    public static T Test<T>() { 
     return TestWith(default(T)); 
     // do something else 
    } 

    public static string TestWith(string dummy) { 
     // Used only for `string`. 
     return "string"; 
    } 

    public static T TestWith<T>(T dummy) { 
     // Used for everything else. 
     return dummy; 
    } 

    static void Main() { 
     Console.WriteLine("Expected \"0\", got \"{0}\"", Test<int>()); 
     Console.WriteLine("Expected \"string\", got \"{0}\"", Test<string>()); 
    } 
} 

Compilato con gmcs, questo rendimenti:

Expected "0", got "0" 
Expected "string", got "" 

Qui, il parametro serve solo per la disambiguazione della chiamata sovraccarico. Parametri generici espliciti non possono essere utilizzati qui poiché una delle funzioni (la specializzazione string) non è generica.

+0

Test chiama ancora TestWith anziché TestWith (stringa) –

+0

Patrick: dannazione. vero. Ero sicuro di averlo già usato. Torna al tavolo da disegno. –

+0

Mi spiace, non capisco quale sia il problema. Puoi fornire un programma che in realtà compila e mostra un output che non ti aspetti? –

2

Prova

public static T Test<T>() where T : class 
{ 
    if (typeof(T) == typeof(string)) return "asdf" as T; // do something else 
    // do something else   
} 
+1

Eseguire un cast "(T)" piuttosto che utilizzare "come T". Quindi è possibile rimuovere la clausola where. – Jehof

+0

@Jehof: ma il codice non verrà più compilato. Quindi no, non farlo. –

+0

@Konrad. Certo che hai ragione. Questo non funziona – Jehof

1

è possibile utilizzare ChangeType?

public static T Test<T>() 
{ 
    if (typeof(T)==typeof(string)) 
     return (T)Convert.ChangeType("1234", typeof(T), CultureInfo.InvariantCulture); 
    return default(T); 
} 
0

ho trovato la soluzione:

public static T Test<T>() 
{ 
    if (typeof(T) == typeof(string)) 
    return (T)(object)"1241"; // this works. 

    // do something else 
} 

Grazie per tutte le risposte .

+0

Si prega di controllare la risposta di Luke, ha trovato la stessa soluzione come voi –

0
public static T Test<T>() 
{ 
    if (typeof(T)==typeof(string)) 
    return (T)Convert.ChangeType("1241", typeof(T)); 

    return default(T); 
} 

io non ho provato, però :-)

Problemi correlati