2009-04-06 12 views
76

Ho MyClass<T>.Come posso ottenere il tipo generico da una rappresentazione di stringa?

E quindi ho questo string s = "MyClass<AnotherClass>";. Come posso ottenere Type dalla stringa s?

Un modo (brutto) è quello di analizzare il "<" e ">" e fare:

Type acType = Type.GetType("AnotherClass"); 
Type whatIwant = typeof (MyClass<>).MakeGenericType(acType); 

Ma c'è un modo più pulito per ottenere il tipo di finale senza alcuna analisi, ecc?

risposta

90

Il format for generics è il nome, un `carattere, il numero di tipo parametri, seguito da un elenco delimitato da virgole dei tipi tra parentesi:

Type.GetType("System.Collections.Generic.IEnumerable`1[System.String]"); 

Non sono sicuro che ci sia un modo semplice per convertire dalla sintassi C# per i generici al tipo di stringa che il CLR vuole. Ho iniziato a scrivere una regex veloce per analizzarla come menzionato nella domanda, ma ho capito che se non si rinuncia alla possibilità di avere generici nidificati come parametri di tipo, l'analisi si complicherebbe molto.

+0

+1 - ottima risposta, grazie! Stavo trafficando cercando di scoprire come gestire i farmaci generici! –

+0

Grazie. Funziona e devo modificare il codice per formattare la stringa in questo modo. Tuttavia, mi chiedevo se c'è ancora un modo per usare semplicemente: "MyClass " esattamente come viene mostrato nella stringa per ottenere l'istanza Type. Sembra molto più pulito. – DeeStackOverflow

+0

Non è necessario modificare il codice per formattare la stringa in questo modo, basta chiamare ToString() sul Tipo. –

38

Partenza Activator.CreateInstance - si può chiamare con un tipo di

Activator.CreateInstance(typeof(MyType)) 

o con un nome di montaggio e tipo string

Activator.CreateInstance("myAssembly", "myType") 

questo vi darà un esempio del tipo di cui avete bisogno.

Se avete bisogno della Type piuttosto che l'istanza, utilizzare il metodo Type.GetType() e il nome completo del tipo che ti interessa, ad esempio:

string s = "System.Text.StringBuilder"; 
Type myClassType = Type.GetType(s); 

Che ti do il Type in questione .

+2

Ciò ottiene solo un esempio del tipo, non un'istanza System.Type, che sulla base del frammento di codice, sembra essere quello OP sta cercando. –

0

Non ho molto tempo per analizzare questo, anche se penso di aver visto alcune risposte simili. In particolare, credo che stanno facendo esattamente quello che si vuole fare qui:

Entity Framework Generic Repository Error

(String.Format("[{0}]", baseType.Name.ToString())).OfType<T>(); 

Speriamo che questo aiuta, me lo faccia sapere più precisamente se questo non lo è.

3

per ottenere solo l'oggetto di tipo dalla stringa, utilizzare:

Type mytype = Type.GetType(typeName); 

È quindi possibile passare questo a Activator.CreateInstance():

Activator.CreateInstance(mytype); 
26

Avevo bisogno di qualcosa di simile e ho finito per scrivere del codice per analizzare i nomi dei tipi semplici di cui avevo bisogno. Naturalmente c'è spazio per miglioramenti, in quanto non identifica nomi di tipi generici come List<string>, ma va bene per string, int[], decimal? e così via. Condivisione nel caso in cui questo aiuti chiunque.

public static class TypeExtensions 
{ 
    public static Type GetTypeFromSimpleName(string typeName) 
    { 
    if (typeName == null) 
     throw new ArgumentNullException("typeName"); 

    bool isArray = false, isNullable = false; 

    if (typeName.IndexOf("[]") != -1) 
    { 
     isArray = true; 
     typeName = typeName.Remove(typeName.IndexOf("[]"), 2); 
    } 

    if (typeName.IndexOf("?") != -1) 
    { 
     isNullable = true; 
     typeName = typeName.Remove(typeName.IndexOf("?"), 1); 
    } 

    typeName = typeName.ToLower(); 

    string parsedTypeName = null; 
    switch (typeName) 
    { 
     case "bool": 
     case "boolean": 
     parsedTypeName = "System.Boolean"; 
     break; 
     case "byte": 
     parsedTypeName = "System.Byte"; 
     break; 
     case "char": 
     parsedTypeName = "System.Char"; 
     break; 
     case "datetime": 
     parsedTypeName = "System.DateTime"; 
     break; 
     case "datetimeoffset": 
     parsedTypeName = "System.DateTimeOffset"; 
     break; 
     case "decimal": 
     parsedTypeName = "System.Decimal"; 
     break; 
     case "double": 
     parsedTypeName = "System.Double"; 
     break; 
     case "float": 
     parsedTypeName = "System.Single"; 
     break; 
     case "int16": 
     case "short": 
     parsedTypeName = "System.Int16"; 
     break; 
     case "int32": 
     case "int": 
     parsedTypeName = "System.Int32"; 
     break; 
     case "int64": 
     case "long": 
     parsedTypeName = "System.Int64"; 
     break; 
     case "object": 
     parsedTypeName = "System.Object"; 
     break; 
     case "sbyte": 
     parsedTypeName = "System.SByte"; 
     break; 
     case "string": 
     parsedTypeName = "System.String"; 
     break; 
     case "timespan": 
     parsedTypeName = "System.TimeSpan"; 
     break; 
     case "uint16": 
     case "ushort": 
     parsedTypeName = "System.UInt16"; 
     break; 
     case "uint32": 
     case "uint": 
     parsedTypeName = "System.UInt32"; 
     break; 
     case "uint64": 
     case "ulong": 
     parsedTypeName = "System.UInt64"; 
     break; 
    } 

    if (parsedTypeName != null) 
    { 
     if (isArray) 
     parsedTypeName = parsedTypeName + "[]"; 

     if (isNullable) 
     parsedTypeName = String.Concat("System.Nullable`1[", parsedTypeName, "]"); 
    } 
    else 
     parsedTypeName = typeName; 

    // Expected to throw an exception in case the type has not been recognized. 
    return Type.GetType(parsedTypeName); 
    } 
} 

suo utilizzo è semplice come scrivere questo:

Type t; 

t = TypeExtensions.GetTypeFromSimpleName("string"); 
t = TypeExtensions.GetTypeFromSimpleName("int[]"); 
t = TypeExtensions.GetTypeFromSimpleName("decimal?"); 
+5

Questo è un bit di codice incredibilmente utile. –

+1

Breve, perfetto, estremamente utile! Grazie – xrnd

Problemi correlati