2013-08-06 10 views
7

Utilizziamo CodeModel di Visual Studio e abbiamo alcuni problemi per ottenere i parametri generici di un CodeType. Come ottenerli senza analizzare personalmente lo FullName?CodeType get generic parameters

Si è accennato (anche se non segnato una risposta) in How can I get the generic constraints from CodeInterface as a CodeType object? che non c'è altro modo, tuttavia, questo non è davvero credibile come:

System.Func<Outer.Inner>

non sarebbe definito: non è possibile sapere se il parametro generico che hai analizzato (Outer.Inner) fa riferimento allo spazio nomi Outer contenente una classe Inner o se si riferisce alla classe Outer con una classe interna Inner (e sì, non è Outer+Inner in questi casi).

Se qualcuno almeno sa come dire alla proprietà FullName di mostrare le classi nidificate con un segno +, anche questo sarebbe ottimo.

risposta

0

Penso che lo answer here sia piuttosto definitivo. Questo non è supportato da DTE o DTE2 ed è improbabile che venga supportato in futuro.

L'unico modo attualmente è utilizzare Roslyn, che non è accettabile per quelli di noi che non vogliono utilizzare il software di pre-release. Inoltre, non ho esaminato il tipo di dipendenze che comportano (gli utenti del mio componente devono installare Roslyn?).

È possibile utilizzare un'espressione regolare per ottenere i tipi dalla stringa FullName. Ma, per quelli di noi nel mondo reale che hanno bisogno del token() per il tipo di cemento (System.String) mappatura, questa non è un'opzione.

0

Non riesco a trovare un modo per farlo per qualsiasi tipo generico, ma se è necessario farlo per un tipo specifico, è possibile in alcuni casi.

Ad esempio, ho il seguente codice per verificare se un tipo è una raccolta, e se lo è, ottenere il tipo di elemento:

private static bool IsCollectionType(CodeType type, out CodeType elementType) 
    { 
     // string implements IEnumerable<char>, but we don't want to treat it as a collection 
     if (type.FullName == "System.String") 
     { 
      elementType = null; 
      return false; 
     } 

     var enumerable = type.Bases.OfType<CodeInterface>().FirstOrDefault(i => i.FullName.StartsWith("System.Collections.Generic.IEnumerable<")); 
     var method = enumerable?.Members.OfType<CodeFunction>().FirstOrDefault(m => m.Name == "GetEnumerator"); 
     var enumerator = method?.Type.CodeType; 
     var current = enumerator?.Members.OfType<CodeProperty>().FirstOrDefault(m => m.Name == "Current"); 
     if (current != null) 
     { 
      elementType = current.Type.CodeType; 
      return true; 
     } 

     elementType = null; 
     return false; 
    } 

Come potete vedere, non sto guardando direttamente l'argomento di tipo generico, ma guardo invece il tipo di IEnumerable<T>.GetEnumerator().Current. Ovviamente, ciò richiede una conoscenza specifica del tipo con cui stai lavorando.