将泛型类型定义字符串从C#样式转换为CLR样式

时间:2010-05-27 23:25:42

标签: c# string generics clr

我想转换C#样式泛型类型字符串,例如:

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

其等效的CLR:

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

然后回来。有没有一种简单的方法可以做到这一点,还是我不得不诉诸字符串操作?

编辑:

我只有C#/ VB / etc样式表单中的字符串表示。我没有Type对象或类似的东西。另一个问题是:如何从"System.Dictionary<System.String, System.String>"之类的字符串表示中获取Type对象(之后我可以获得类型对象的全名)。

编辑#2:

理由:我正在使用CodeDom动态创建对象。我正在生成CodeDom的输入可能包含C#(或任何其他专有的VB.NET)格式的类型,但我必须在CodeTypeReference内使用它们,只接受CLR样式格式。

6 个答案:

答案 0 :(得分:4)

对于.NET到C#的方向,我看不到一个简单的方法;你可能必须亲自解析这个类型。

在另一个方向,这很容易:

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

答案 1 :(得分:2)

我相信我过去遇到过类似的问题,并编写了以下实用程序方法来解决它:

    // 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.");

答案 2 :(得分:0)

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

至于反过来,没有线索:(

答案 3 :(得分:0)

我不确定我完全理解你的问题。 无论如何 - 当您实例化名称空间命名空间中定义的遗传类Class<T1, ... ,Tn>时,例如

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

a.GetType()。FullName将为您提供该类的完整字符串表示形式 这将是"Namespace.Class'n<Type1,...,Typen>"

答案 4 :(得分:0)

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]");

编辑我曾尝试使用动态表达式进行黑客攻击,但没有太多运气。我认为,除了解析字符串之外,您可以使用“核选项”并使用CSharpCodeProvider编译DLL,然后使用Assembly.LoadFile加载它并执行将评估typeof(...)的方法。

答案 5 :(得分:0)

我认为这就是你要找的......

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

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