2009-04-06 10 views
76

Mam MyClass<T>.Jak uzyskać ogólny typ z reprezentacji ciągów znaków?

A potem mam to string s = "MyClass<AnotherClass>";. Jak mogę uzyskać typ z ciągu s?

Jednym ze sposobów (brzydki) jest do analizowania zewnątrz „<” i „>”, a następnie zrobić:

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

Ale czy istnieje sposób, aby uzyskać czystsze ostateczny typ bez analizowania, itp?

Odpowiedz

90

format for generics to nazwa, od `charakter, liczba parametrów typu, po których następuje lista rozdzielana przecinkami w nawiasach:

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

Nie jestem pewien, czy istnieje łatwy sposób konwersji ze składni C# dla generycznych na typ ciągu, który chce CLR. Zacząłem pisać szybkie wyrażenie, aby je przetworzyć, tak jak wspomniałeś w pytaniu, ale zdałem sobie sprawę, że dopóki nie zrezygnujesz z możliwości zagnieżdżenia generycznych jako parametrów typu, parsowanie stanie się bardzo skomplikowane.

+0

+1 - wspaniała odpowiedź, dzięki! Bawiłem się, próbując dowiedzieć się, jak poradzić sobie z lekami generycznymi! –

+0

Dzięki. To działa i muszę zmodyfikować kod, aby sformatować ciąg w ten sposób. Zastanawiał się jednak, czy nadal istnieje sposób, aby po prostu użyć: "MyClass " dokładnie tak, jak jest pokazany w ciągu znaków, aby uzyskać instancję typu. Wygląda o wiele czystsze. – DeeStackOverflow

+0

Nie musisz modyfikować kodu, aby sformatować ciąg znaków w ten sposób, wystarczy wywołać ToString() na typie. –

38

Wyjazd Activator.CreateInstance - można nazwać to z typem

Activator.CreateInstance(typeof(MyType)) 

lub z nazwą zespołu i typu jak string

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

to daje instancję typu trzeba.

Jeśli potrzebujesz Type zamiast instancji, należy użyć metody Type.GetType() oraz pełną nazwę typu, który Cię interesuje, np

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

To da Ci Type w pytaniu .

+2

To po prostu staje się wystąpienie typu, a nie np System.Type, która opiera się na fragmencie kodu, co wydaje się być OP szuka. –

0

Nie mam zbyt wiele czasu na przeanalizowanie tego, choć wydaje mi się, że widziałem podobne odpowiedzi. W szczególności, myślę, że robią dokładnie to, co chcesz zrobić tutaj:

Entity Framework Generic Repository Error

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

Mam nadzieję, że to pomaga, daj mi znać, a dokładniej, czy to nie jest.

3

po prostu uzyskać obiektu typu z ciągu znaków, należy:

Type mytype = Type.GetType(typeName); 

można następnie przekazać to Activator.CreateInstance():

Activator.CreateInstance(mytype); 
26

Potrzebowałem czegoś takiego i skończyło się na tym, że napisałem kod, by przetworzyć proste nazwy, których potrzebowałem. Oczywiście jest miejsce na ulepszenia, ponieważ nie będzie identyfikować ogólnych nazw typów, takich jak List<string>, ale jest w porządku dla string, int[], decimal? i innych. Dzielenie się w przypadku, gdy to pomaga każdemu.

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

Używanie go jest tak proste, jak pisanie to:

Type t; 

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

To niesamowicie użyteczny fragment kodu. –

+1

Krótkie, doskonałe, wyjątkowo przydatne! Dzięki – xrnd

Powiązane problemy