J'ai MyClass<T>
.
Et puis j'ai ce string s = "MyClass<AnotherClass>";
. Comment puis-je obtenir Type à partir de la chaîne s
?
Une façon (moche) est d'analyser les "<" et ">" et de faire:
Type acType = Type.GetType("AnotherClass");
Type whatIwant = typeof (MyClass<>).MakeGenericType(acType);
Mais existe-t-il un moyen plus propre d'obtenir le type final sans analyse, etc.?
Le format pour les génériques est le nom, un caractère `, le nombre de paramètres de type, suivi d'une liste délimitée par des virgules des types entre parenthèses:
Type.GetType("System.Collections.Generic.IEnumerable`1[System.String]");
Je ne suis pas sûr qu'il existe un moyen facile de convertir de la syntaxe C # pour les génériques au type de chaîne que le CLR veut. J'ai commencé à écrire une expression rationnelle rapide pour l'analyser comme vous l'avez mentionné dans la question, mais j'ai réalisé qu'à moins que vous n'abandonniez la possibilité d'avoir des génériques imbriqués comme paramètres de type, l'analyse sera très compliquée.
Découvrez Activator.CreateInstance
- vous pouvez l'appeler avec un type
Activator.CreateInstance(typeof(MyType))
ou avec un assembly et tapez le nom comme string
Activator.CreateInstance("myAssembly", "myType")
Cela vous donnera une instance du type dont vous avez besoin.
Si vous avez besoin de Type
plutôt que de l'instance, utilisez la méthode Type.GetType()
et le nom complet du type qui vous intéresse, par exemple:
string s = "System.Text.StringBuilder";
Type myClassType = Type.GetType(s);
Cela vous donnera le Type
en question.
J'ai eu besoin de quelque chose comme ça et j'ai fini par écrire du code pour analyser les noms de type simples dont j'avais besoin. Bien sûr, il y a place à amélioration, car il n'identifiera pas les noms de type génériques comme List<string>
, mais ça marche très bien pour string
, int[]
, decimal?
et autres choses de ce genre. Partager au cas où cela aiderait quelqu'un.
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);
}
}
Son utilisation est aussi simple que d'écrire ceci:
Type t;
t = TypeExtensions.GetTypeFromSimpleName("string");
t = TypeExtensions.GetTypeFromSimpleName("int[]");
t = TypeExtensions.GetTypeFromSimpleName("decimal?");
Pour obtenir simplement l'objet type de la chaîne, utilisez:
Type mytype = Type.GetType(typeName);
Vous pouvez ensuite transmettre ceci à Activator.CreateInstance()
:
Activator.CreateInstance(mytype);
Je n'ai pas beaucoup de temps pour analyser cela, bien que je pense avoir vu des réponses similaires. En particulier, je pense qu'ils font exactement ce que vous voulez faire ici:
Erreur de référentiel générique Entity Framework
(String.Format("[{0}]", baseType.Name.ToString())).OfType<T>();
J'espère que cela aide, faites-moi savoir plus précisément si ce n'est pas le cas.