2010-05-27 9 views
3

Je veux convertir un style C# type générique chaîne, comme:Convertir les chaînes de définition de type générique de type C# style CLR

"System.Dictionary<System.String, System.String>" 

Pour son équivalent CLR:

"System.Dictionary`1[System.String, System.String]" 

et retour . Existe-t-il un moyen facile de le faire, ou dois-je recourir à la manipulation de chaînes?

EDIT:

ne me reste que la représentation de chaîne en C#/VB/etc sous forme de style. Je n'ai pas d'objet Type ou quelque chose de similaire sous la main. Une autre question aurait été: comment obtenir un objet Type à partir d'une représentation sous forme de chaîne comme "System.Dictionary<System.String, System.String>" (après cela, je peux obtenir le nom complet de l'objet type).

EDIT # 2:

Justification: Je crée des objets dynamiquement à l'aide CodeDom. L'entrée à partir de laquelle je génère le CodeDom peut contenir des types au format C# (ou tout autre format propriétaire tel que VB.NET), mais je dois les utiliser dans un CodeTypeReference, qui n'accepte que le format de style CLR.

+0

Vous cherchez beaucoup de douleur si vous essayez de convertir le style 'C#' au type .Net actuel. Votre meilleur pari est de créer une table de correspondance liée à votre code CodeDOM. Il contiendrait la liste des types 'C#' et des noms de types .Net. –

Répondre

2

Je crois que je fait face à un problème similaire dans le passé et écrit la méthode utilitaire suivante pour y remédier:

// Utilitiy to convert class name string to namespace-qualified name 
    public static Type GetTypeByName(string ClassName, 
     string TypesNamespacePrefix = "AssemblyTopLevel.AssemblyMidLevel.", 
     Dictionary<string, Type> ConcreteTypeMap = null) 
    { 
     if ((ConcreteTypeMap != null) && (ConcreteTypeMap.ContainsKey(ClassName))) 
      return ConcreteTypeMap[ClassName]; 

     if ((ConcreteTypeMap != null) && (ConcreteTypeMap.ContainsKey(TypesNamespacePrefix + ClassName))) 
      return ConcreteTypeMap[TypesNamespacePrefix + ClassName]; 

     try 
     { 
      if (Type.GetType(ClassName) != null) 
       return Type.GetType(ClassName); 
     } 
     catch { } 

     try 
     { 
      if (Type.GetType(TypesNamespacePrefix + ClassName) != null) 
       return Type.GetType(TypesNamespacePrefix + ClassName); 
     } 
     catch { } 

     Stack<int> GenericCounterStack = new Stack<int>(); 
     Stack<int> GenericStartIndexStack = new Stack<int>(); 
     Dictionary<int, int> GenericCountMapByStartIndex = new Dictionary<int, int>(); 
     int Count = 1; 
     int GenericStartIndex = -1; 
     int PreviousHighestGenericIndex = -1; 

     foreach (char c in ClassName) 
     { 
      if (c.Equals('<')) 
      { 
       if (GenericStartIndex != -1) 
       { 
        GenericCounterStack.Push(Count); 
        GenericStartIndexStack.Push(GenericStartIndex); 
       } 
       Count = 1; 
       GenericStartIndex = PreviousHighestGenericIndex + 1; 
       PreviousHighestGenericIndex = Math.Max(GenericStartIndex, PreviousHighestGenericIndex); 
      } 
      else if (c.Equals(',')) 
      { 
       Count++; 
      } 
      else if (c.Equals('>')) 
      { 
       GenericCountMapByStartIndex[GenericStartIndex] = Count; 
       if (GenericCounterStack.Count != 0) 
        Count = GenericCounterStack.Pop(); 
       if (GenericStartIndexStack.Count != 0) 
        GenericStartIndex = GenericStartIndexStack.Pop(); 
      } 
     } 

     ClassName = ClassName.Replace("<" + TypesNamespacePrefix, "<"); 

     StringBuilder FullyQualifiedClassName = new StringBuilder(TypesNamespacePrefix); 

     GenericStartIndex = 0; 
     foreach (char c in ClassName) 
     { 
      if (c.Equals('<')) 
      { 
       FullyQualifiedClassName.Append("`" + GenericCountMapByStartIndex[GenericStartIndex].ToString() 
        + "[" + TypesNamespacePrefix); 
       GenericStartIndex++; 
      } 
      else if (c.Equals(',')) 
      { 
       FullyQualifiedClassName.Append("," + TypesNamespacePrefix); 
      } 
      else if (c.Equals('>')) 
      { 
       FullyQualifiedClassName.Append("]"); 
      } 
      else 
       FullyQualifiedClassName.Append(c); 
     } 

     ClassName = FullyQualifiedClassName.ToString(); 

     return Type.GetType(ClassName); 
    } 

Vous pouvez en option fournir une carte de type concret, à optimiser pour les cas couramment invoqués:

static readonly Dictionary <string, Type> MyConcreteTypeMap = new Dictionary<string,Type>() 
    { 
     {"SomeClass", typeof(SomeClass)}, 
     {"AnotherClass", typeof(AnotherClass)} 
    } 

Ainsi, l'invocation ressemble à ceci:

Type DesiredType = GetTypeByName("SomeClass", "", MyConcreteTypeMap); 

ou

Type DesiredType = GetTypeByName("SomeOtherClass", "MyAssemblyTopLevel.MyAssemblyMidLevel."); 

ou

Type DesiredType = GetTypeByName("SomeOtherClass"); 

ou, tout à fait utile,

Type DesiredType = GetTypeByName("SomeOtherClass<OuterTemplate<InnerTemplate1,InnerTemplate2<InnerInnerTemplate1>>>"); 

ou, pour l'exemple d'origine ,

Type DesiredType = GetTypeByName("Dictionary<String,String>", "System."); 
0
typeof(System.Dictionary<System.String>, System.String>).FullName 

Quant à l'inverse, aucun indice :(

0

Je ne suis pas sûr que je comprends parfaitement votre question. De toute façon -Lorsque vous instancier une classe génétique Class<T1, ... ,Tn> le défini dans l'espace de noms Namespace, par exemple

Namespace.Class<T1, ... ,Tn> a = new Namespace.Class<Type1,...,Typen>(); 

a.GetType(). FullName vous donnera la représentation chaîne complète de la classe qui sera "Namespace.Class'n<Type1,...,Typen>"

0

typeof(System.Dictionary<System.String, System.String>).FullName devrait vous obtenir quelque chose comme:

System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] 

pourrions avoir besoin de faire un peu remplacer les noms de type complet à l'intérieur du spec de paramètre de type. Toutefois, si vous utilisez le code ci-dessous

typeof(Dictionary<System.String, System.String>).ToString() 

Vous obtiendrez quelque chose comme ceci:

System.Collections.Generic.Dictionary`2[System.String,System.String] 

Pour reconvertir en une Type utilisation

Type.GetType("System.Collections.Generic.Dictionary`2[System.String,System.String]"); 

EDIT J'ai essayé de piratage ceci avec des expressions dynamiques mais n'a pas eu beaucoup de chance. Je pense, autre que l'analyse de la chaîne, vous pouvez utiliser une "option nucléaire" et compiler une DLL en utilisant CSharpCodeProvider, puis le charger en utilisant Assembly.LoadFile et exécuter une méthode qui évaluera typeof (...).

+0

Je n'ai que la représentation sous forme de chaîne du type en style C#. Voir éditer. – SztupY

+0

Hmm. Pas quelque chose que l'on voudrait faire normalement. Si vous avez du code C#, vous le compilez. Si vous avez une représentation sous forme de chaîne d'un type, elle est normalement sérialisée en chaîne puis désérialisée. Ces deux cas sont pris en charge par le cadre. Pourriez-vous fournir plus de contexte sur ce que vous faites? –

+0

pour le contexte, voir edit2. – SztupY

0

Je pense que c'est ce que vous cherchiez ...

var dict = new Dictionary<string, string>(); 
var type = dict.GetType(); 
var typeName = type.FullName; 
var newType = Type.GetType(typeName); 

Console.WriteLine(type == newType); //true 
+0

Je n'ai que la représentation sous forme de chaîne du type dans le style C# – SztupY

+0

@SztupY: Si vous voulez créer une instance de l'objet/type, vous pouvez utiliser CodeDom au lieu de manipuler les chaînes. Mais le meilleur pari serait probablement d'écrire une sorte de convertisseur/analyseur pour les valeurs de chaîne. C'est une option pour remplacer les valeurs de style 'C#' avec la bonne 'Type.FullName' ou' Type.AssemblyQualifiedName'? –

+0

Lien de référence CodeDOM ... http://msdn.microsoft.com/en-us/library/f1dfsbhc.aspx –

4

Pour la direction .NET vers C#, je ne vois pas de moyen facile de le faire; vous devrez peut-être analyser le type vous-même.

Dans l'autre sens, il est assez facile:

public static string DotNetToCSharp(string tyName) { 
    var provider = new Microsoft.CSharp.CSharpCodeProvider(); 
    return provider.GetTypeOutput(new System.CodeDom.CodeTypeReference(tyName)); 
} 
+0

pour l'autre sens, il semble que je doive recourir à codesnippets (ou analyser à la main) – SztupY

Questions connexes