Преобразование строк определения универсального типа из стиля C # в стиль CLR - PullRequest
3 голосов
/ 28 мая 2010

Я хочу преобразовать универсальный тип в стиле C # string , например:

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

В эквиваленте CLR:

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

и обратно. Есть ли простой способ сделать это, или я должен прибегнуть к манипуляции со строками?

РЕДАКТИРОВАТЬ:

У меня есть только строковое представление в форме стиля C # / VB / etc. У меня нет объекта Type или чего-то подобного под рукой. Альтернативный вопрос был бы: как получить объект Type из строкового представления, такого как "System.Dictionary<System.String, System.String>" (после этого я могу получить полное имя объекта типа).

РЕДАКТИРОВАТЬ # 2:

Обоснование: я создаю объекты динамически, используя CodeDom. Входные данные, из которых я генерирую CodeDom, могут содержать типы в формате C# (или любом другом проприетарном, например, VB.NET), но я должен использовать их внутри CodeTypeReference, который принимает только формат стиля CLR .

Ответы [ 6 ]

4 голосов
/ 28 мая 2010

Для направления .NET в C # я не вижу простого способа сделать это; возможно, вам придется проанализировать тип самостоятельно.

В другом направлении это довольно просто:

public static string DotNetToCSharp(string tyName) {
    var provider = new Microsoft.CSharp.CSharpCodeProvider();
    return provider.GetTypeOutput(new System.CodeDom.CodeTypeReference(tyName));
}
2 голосов
/ 02 сентября 2014

Мне кажется, я сталкивался с подобной проблемой в прошлом и написал следующий метод для ее устранения:

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

При желании вы можете предоставить конкретную карту типов, чтобы оптимизировать ее для часто используемых случаев:

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

Итак, вызов выглядит так:

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

или

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

или

Type DesiredType = GetTypeByName("SomeOtherClass");

или, весьма полезно,

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

или, для исходного примера,

Type DesiredType = GetTypeByName("Dictionary<String,String>", "System.");
0 голосов
/ 28 мая 2010

Я думаю, это то, что вы искали ...

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 голосов
/ 28 мая 2010

typeof(System.Dictionary<System.String, System.String>).FullName должно дать вам что-то вроде:

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]]

Возможно, потребуется выполнить некоторую замену полных имен типов внутри спецификации параметра типа. Однако, если вы используете код ниже

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

Вы получите что-то вроде этого:

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

Чтобы преобразовать обратно в Type, используйте

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

РЕДАКТИРОВАТЬ Я пытался взломать это с помощью динамических выражений, но мне не повезло. Я думаю, кроме анализа строки, вы можете использовать «ядерную опцию» и скомпилировать DLL, используя CSharpCodeProvider, а затем загрузить ее с помощью Assembly.LoadFile и выполнить метод оценит typeof (...).

0 голосов
/ 28 мая 2010

Я не уверен, что полностью понимаю ваш вопрос. В любом случае, когда вы создаете экземпляр генетического класса Class<T1, ... ,Tn>, определенного в пространстве имен пространства имен, например

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

a.GetType (). FullName предоставит вам полное строковое представление класса который будет "Namespace.Class'n<Type1,...,Typen>"

0 голосов
/ 28 мая 2010
typeof(System.Dictionary<System.String>, System.String>).FullName

Что касается обратного, без понятия: (

...