【问题标题】:Correct way to obtain base name of a generic type in .NET is through Substring?在.NET 中获取泛型类型的基本名称的正确方法是通过子字符串?
【发布时间】:2010-11-24 03:59:19
【问题描述】:

如果我有这个:

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>

编辑:好的,这是最终代码,对我来说仍然有点像 hack,但它确实有效:

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

【问题讨论】:

    标签: c# .net reflection types


    【解决方案1】:

    AFAIK 泛型的内部符号使用 `x 符号来指示泛型类型的类型参数的数量。 IE。 2 表示 Dictionary 需要两种类型来关闭它。它与 ILDasm 和 Reflection 使用的符号相同。

    【讨论】:

    • 正确,但正如我所展示的那样,这是通过使用子字符串在通用部分之前获取名称部分的唯一方法,或者是否有更整洁的反射方式、我不使用的属性或方法不知道吗?
    • 正如 JohannesH 在他的回答中指出的那样,您看到的是 IL 表示法。如果你想要其他东西(比如 C#),你需要自己映射它。我们有几个内部工具可以执行类似于您建议的操作。我不知道任何其他获取 C# 语法的方法,但另一方面,我会假设格式是固定的,因此您应该能够自己安全地转换它。
    【解决方案2】:

    问题是您需要一种特定于语言的表示法,在本例中为 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】:

    您可以使用 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>    
    

    无需任何自定义类型字符串化代码,您就可以得到大部分您想要的东西。

    【讨论】:

      【解决方案4】:

      这是否更接近您的目标?

      它使用CodeTypeReferenceExpression 并且不需要任何进一步的SubstringReplace 调用:

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

      【讨论】:

      • @John:你是对的,但这并不意味着这个答案是错误的和/或值得一票否决。此外,问题询问如何在不进行额外字符串操作的情况下执行此操作,而 bobbymcr 的回答仍然需要Replace 调用。
      猜你喜欢
      • 2014-10-18
      • 1970-01-01
      • 2017-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-08
      • 1970-01-01
      相关资源
      最近更新 更多