代码之家  ›  专栏  ›  技术社区  ›  Lasse V. Karlsen

在.NET中通过子字符串获取泛型类型的基名称的正确方法是?

  •  8
  • Lasse V. Karlsen  · 技术社区  · 16 年前

    如果我有这个:

    Type t = typeof(Dictionary<String, String>);
    

    我如何得到 "System.Collections.Generic.Dictionary" 作为字符串?最好/唯一的方法是:

    String n = t.FullName.Substring(0, t.FullName.IndexOf("`"));
    

    不过在我看来有点老土。

    我想要这个的原因是我想要一个 Type 对象,并生成与C源代码文件中的代码类似的代码。我正在生成一些文本模板,我需要将类型作为字符串添加到源中,并且 FullName 属性产生如下内容:

    System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0,
    Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0,
    Culture=neutral, PublicKeyToken=b77a5c561934e089]]
    

    而不是我想要的:

    System.Collections.Generic.Dictionary<System.String, System.String>
    

    编辑 :好的,这是最后一个代码,在我看来还是有点像黑客,但它是有效的:

    /// <summary>
    /// This method takes a type and produces a proper full type name for it, expanding generics properly.
    /// </summary>
    /// <param name="type">
    /// The type to produce the full type name for.
    /// </param>
    /// <returns>
    /// The type name for <paramref name="type"/> as a string.
    /// </returns>
    /// <exception cref="ArgumentNullException">
    /// <para><paramref name="type"/> is <c>null</c>.</para>
    /// </exception>
    public static String TypeToString(Type type)
    {
        #region Parameter Validation
    
        if (Object.ReferenceEquals(null, type))
            throw new ArgumentNullException("type");
    
        #endregion
    
        if (type.IsGenericType)
        {
            if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                Type underlyingType = type.GetGenericArguments()[0];
                return String.Format("{0}?", TypeToString(underlyingType));
            }
            String baseName = type.FullName.Substring(0, type.FullName.IndexOf("`"));
            return baseName + "<" + String.Join(", ", (from paramType in type.GetGenericArguments()
                                                       select TypeToString(paramType)).ToArray()) + ">";
        }
        else
        {
            return type.FullName;
        }
    }
    
    4 回复  |  直到 10 年前
        1
  •  6
  •   bobbymcr    16 年前

    您可以使用codedom生成一个更“普通”的C样式声明。

    CodeDomProvider csharpProvider = CodeDomProvider.CreateProvider("C#");
    CodeTypeReference typeReference = new CodeTypeReference(typeof(Dictionary<string, int>));
    CodeVariableDeclarationStatement variableDeclaration = new CodeVariableDeclarationStatement(typeReference, "dummy");
    StringBuilder sb = new StringBuilder();
    using (StringWriter writer = new StringWriter(sb))
    {
        csharpProvider.GenerateCodeFromStatement(variableDeclaration, writer, new CodeGeneratorOptions());
    }
    
    sb.Replace(" dummy;", null);
    Console.WriteLine(sb.ToString());
    

    上述代码具有以下输出:

    System.Collections.Generic.Dictionary<string, int>    
    

    在没有任何自定义类型字符串化代码的情况下,这应该可以满足您的大部分需求。

        2
  •  7
  •   JohannesH    16 年前

    问题是您需要一个特定于语言的符号,在本例中是C。

    IL syntax:     [mscorlib]System.Collections.Generic.Dictionary`2<class [mscorlib]System.String, class [mscorlib]System.String>
    C# syntax:     System.Collections.Generic.Dictionary<System.String, System.String>
    VB.NET syntax: System.Collections.Generic.Dictionary(Of System.String, system.String)
    

    也许你可以调用一个语言服务来获取你想要的字符串,但是你可能更擅长自己生成字符串。

        3
  •  3
  •   LukeH    16 年前

    这离你要找的更近吗?

    它使用 CodeTypeReferenceExpression 不需要更多 Substring Replace 电话:

    var type = typeof(Dictionary<string, string>);
    Console.WriteLine(TypeToString(type));
    
    // ...
    
    public static string TypeToString(Type type)
    {
        if (type == null) throw new ArgumentNullException("type");
    
        var sb = new StringBuilder();
        using (var sw = new StringWriter(sb))
        {
            var expr = new CodeTypeReferenceExpression(type);
    
            var prov = new CSharpCodeProvider();
            prov.GenerateCodeFromExpression(expr, sw, new CodeGeneratorOptions());
        }
        return sb.ToString();
    }
    
        4
  •  2
  •   Brian Rasmussen    16 年前

    afaik泛型的内部表示法使用'x表示法指示泛型类型的类型参数数目。即2表示字典需要两种类型来关闭它。它与ildasm和reflection使用的符号相同。