2013-08-06 11 views
7

Używamy Visual Studio CodeModel i mamy pewne problemy, aby uzyskać ogólne parametry CodeType. Jak je uzyskać bez sami analizowania FullName?CodeType pobierz ogólne parametry

Jest zrozumienia (choć nie zaznaczono odpowiedź) w How can I get the generic constraints from CodeInterface as a CodeType object?, że nie ma innego wyjścia, jednak nie jest to wiarygodny jako:

System.Func<Outer.Inner>

nie byłoby zdefiniowane: Nie możesz wiedzieć, czy parametr ogólny, który przeanalizowałeś (Outer.Inner) odnosi się do przestrzeni nazw Outer zawierającej klasę Inner lub jeśli odnosi się do klasy Outer posiadającej wewnętrzną klasę Inner (i tak, w takich przypadkach nie jest to Outer+Inner).

Jeśli ktoś przynajmniej wie, jak odróżnić właściwość FullName, aby wyświetlać klasy zagnieżdżone znakiem +, byłoby to również wspaniałe.

Odpowiedz

0

Myślę, że answer here jest dość ostateczny. Nie jest to obsługiwane przez DTE lub DTE2 i jest mało prawdopodobne, że będzie obsługiwane w przyszłości.

Obecnie jedynym sposobem jest użycie Roslyn, co jest niedopuszczalne dla tych z nas, którzy nie chcą używać oprogramowania przedpremierowego. Nie sprawdzałem również, jakie rodzaje zależności będą się wiązały z tym, że użytkownicy mojego komponentu muszą zainstalować Roslyn?).

Możesz może użyć wyrażenia regularnego, aby uzyskać typy z ciągu FullName. Ale dla tych z nas w świecie rzeczywistym, którzy potrzebują tokena (T) do mapowania typu konkretnego (System.String), nie jest to opcja.

0

Nie mogę znaleźć sposobu, aby zrobić to dla dowolnego rodzaju ogólnego, ale jeśli musisz zrobić to dla określonego typu, jest to możliwe w niektórych przypadkach.

Na przykład, mam następujący kod, aby sprawdzić, czy typ jest zbiorem, a jeżeli tak, to uzyskać typ elementu:

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; 
    } 

Jak widać, nie jestem bezpośrednio patrząc na ogólny typ argumentu, ale zamiast tego patrzę na typ IEnumerable<T>.GetEnumerator().Current. Oczywiście wymaga to konkretnej wiedzy o typie, z którym pracujesz.