2009-08-30 26 views
8

如果我有这样的:在.NET中获取泛型类型基名的正确方法是通过Substring?

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

如何获得"System.Collections.Generic.Dictionary"作为一个字符串?是最好的/唯一的方法来做到这一点:

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

虽然似乎有点hackish。

我想要这个的原因是我想要一个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; 
    } 
} 

回答

6

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

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

+0

正确的,但是是唯一的方法,通过使用子字符串中的通用部分之前得到名称的一部分,因为我发现,还是有一种整洁的反思方式,一种我不知道的财产或方法? – 2009-08-30 16:50:25

+0

正如JohannesH在他的回答中指出的那样,你看到的是IL符号。如果你想要别的东西(比如C#),你需要自己映射它。我们有几个内部工具可以完成类似于您的建议。我不知道有任何其他方法来获得C#语法,但另一方面,我会假定格式被修复,因此您应该能够自己安全地转换它。 – 2009-08-30 17:04:16

7

问题是你想要一种语言特定的符号,在这种情况下,C#。

​​

也许你可以调用语言服务来获得你想要的字符串,但你可能会更好的与产生自己的字符串。

+0

好的,我将保留原来的代码。 – 2009-08-30 17:23:27

+0

MSDN文档使用C#语法(标题除外):http://msdn.microsoft.com/en-us/library/xfhwa508.aspx – 2011-04-07 15:23:45

+0

@Chris,您可以选择MSDN使用它没有的表示成为C#。 – JohannesH 2011-04-08 10:47:47

3

这更接近您要找的内容吗?

它采用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(); 
} 
+0

@John:你说的对,但这并不意味着这个答案是错误的和/或值得赞成的。此外,问题是如何在没有额外的字符串操作的情况下做到这一点,而bobbymcr的答案仍然需要一个'Replace'调用。 – LukeH 2009-09-01 15:54:57