代码之家  ›  专栏  ›  技术社区  ›  SztupY

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

  •  3
  • SztupY  · 技术社区  · 15 年前

    我要转换C样式的泛型类型 一串 ,像:

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

    其CLR等效物:

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

    然后回来。有没有一个简单的方法可以做到这一点,或者我必须求助于字符串操作?

    编辑:

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

    编辑第2页:

    对正:我正在使用 CodeDom . 从中生成 代码树 可能包含类型 C# (或任何其他专有的,如vb.net)格式,但我必须在 CodeTypeReference ,它只接受CLR样式格式。

    6 回复  |  直到 11 年前
        1
  •  2
  •   paulparayil    11 年前

    我相信我过去也遇到过类似的问题,为此我写了以下实用方法:

        // 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
  •  4
  •   kvb    15 年前

    对于.NET到C方向,我看不到一个简单的方法;您可能需要自己实际分析类型。

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

    public static string DotNetToCSharp(string tyName) {
        var provider = new Microsoft.CSharp.CSharpCodeProvider();
        return provider.GetTypeOutput(new System.CodeDom.CodeTypeReference(tyName));
    }
    
        3
  •  0
  •   Aren    15 年前
    typeof(System.Dictionary<System.String>, System.String>).FullName
    

    至于反面,没有线索:(

        4
  •  0
  •   Itay Karo    15 年前

    我不确定我完全理解你的问题。 不管怎样-当你实例化一个基因类时 Class<T1, ... ,Tn> 例如,在命名空间命名空间中定义的

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

    a.getType().fullName将为您提供类的完整字符串表示形式。 将会是什么 "Namespace.Class'n<Type1,...,Typen>"

        5
  •  0
  •   Matthew Whited    15 年前

    我想这就是你要找的…

    var dict = new Dictionary<string, string>();
    var type = dict.GetType();
    var typeName = type.FullName;
    var newType = Type.GetType(typeName);
    
    Console.WriteLine(type == newType); //true
    
        6
  •  0
  •   Igor Zevaka    15 年前

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

    编辑 我试过用动态表达式来破解这个问题,但运气不太好。我认为,除了解析字符串,您可以使用“nuclear选项”并使用 CSharpCodeProvider 然后用加载 Assembly.LoadFile 并执行一个方法来计算typeof(…)。