通过反射获取的类型,是否可以获得“C#名称”:
System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
我希望得到:
List<String>
不需要分割字符串吗?例如,使用反射。
谢谢!
通过反射获取的类型,是否可以获得“C#名称”:
System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
我希望得到:
List<String>
不需要分割字符串吗?例如,使用反射。
谢谢!
不能直接得到,但你可以检查类型本身来确定它。
public static string TypeName(Type t) {
if (!t.IsGenericType) return t.Name;
StringBuilder ret = new StringBuilder();
ret.Append(t.Name).Append("<");
bool first = true;
foreach(var arg in t.GetGenericArguments()) {
if (!first) ret.Append(", ");
first = false;
ret.Append(TypeName(arg));
}
ret.Append(">");
return ret.ToString();
}
ret.Append(string.Join(", ", t.GetGenericArguments().Select(t => TypeName(t)).ToArray()));
- Lasse V. Karlsen是的,您可以使用CodeDom
和CSharpCodeProvider
而不必拆分、解析或操作字符串来完成此操作:
using CodeDom;
using Microsoft.CSharp;
// ...
Type yourType = typeof(List<string>); // for example
using (var provider = new CSharpCodeProvider())
{
var typeRef = new CodeTypeReference(yourType);
Console.WriteLine(provider.GetTypeOutput(typeRef));
}
List<string>
而不是System.Collections.Generic.List<string>
。)t`x[[a(,b,c,d)]]
其中t是实际类型;x - 泛型参数的数量;a、b、c、d等 - 泛型参数
您可以检查类型以确定它是否嵌套,以及它是否是泛型构造还是原始类型。特别是我已经意识到,嵌套的泛型类型会在类型名称字符串的末尾列出其泛型参数。这在文档Type.GetType Method (String)中提到。
我已经部分解决了任务,并且我的解决方案通过了以下测试。
[TestMethod]
public void Tests()
{
Assert.AreEqual("int",typeof(int).ToCSharpMethodReturnTypeName());
Assert.AreEqual("int[]",typeof(int[]).ToCSharpMethodReturnTypeName());
Assert.AreEqual("int?", typeof(int?).ToCSharpMethodReturnTypeName());
Assert.AreEqual("UnitTypeFriendlyNamesExtensionsTest.Inner2<string,IDictionary<string,object>>.SubInner<int,List<byte[]>,object>", typeof(Inner2<string,IDictionary<string,object>>.SubInner<int,List<byte[]>,object>).ToCSharpMethodReturnTypeName());
Assert.ThrowsException<NotImplementedException>(()=> typeof(Inner2<string, IDictionary<string, object>>.SubInner<int, List<byte[]>, object>).DeclaringType.ToCSharpMethodReturnTypeName());
var t = typeof(TestGenericReturnType<DateTime>);
var m = t.GetMethod("GetService");
var tt = m.ReturnType;
Assert.AreEqual("DateTime",tt.ToCSharpMethodReturnTypeName());
Assert.AreEqual("IDictionary<string,object>",typeof(IDictionary<string,object>).ToCSharpMethodReturnTypeName());
Assert.AreEqual("IList<int[]>",typeof(IList<int[]>).ToCSharpMethodReturnTypeName());
Assert.AreEqual("UnitTypeFriendlyNamesExtensionsTest.Astruc?",typeof(Astruc?).ToCSharpMethodReturnTypeName());
Assert.AreEqual("UnitTypeFriendlyNamesExtensionsTest.Inner", typeof(Inner).ToCSharpMethodReturnTypeName());
}
扩展类处理嵌套和泛型构造类型以及基本类型。
public static class TypeFriendlyNamesExtensions
{
private static readonly Dictionary<Type, string> TypeToFriendlyName = new Dictionary<Type, string>
{
{typeof(string), "string"},
{typeof(object), "object"},
{typeof(bool), "bool"},
{typeof(byte), "byte"},
{typeof(char), "char"},
{typeof(decimal), "decimal"},
{typeof(double), "double"},
{typeof(short), "short"},
{typeof(int), "int"},
{typeof(long), "long"},
{typeof(sbyte), "sbyte"},
{typeof(float), "float"},
{typeof(ushort), "ushort"},
{typeof(uint), "uint"},
{typeof(ulong), "ulong"},
{typeof(void), "void"}
};
public static string ToCSharpMethodReturnTypeName(this Type type)
{
var sb = new StringWriter();
ToCSharpNameEntry2(sb, type);
return sb.ToString();
}
private static void ToCSharpNameEntry2(TextWriter sb, Type type0)
{
var list = GetContainingTypeList(type0);
var usedGenericArgumentCounter = 0;
HandleNestedLevel(sb, list, 0, ref usedGenericArgumentCounter);
foreach (var ix in Enumerable.Range(1, list.Count - 1))
{
sb.Write(".");
HandleNestedLevel(sb, list, ix, ref usedGenericArgumentCounter);
}
}
private static void HandleNestedLevel(TextWriter sb, IReadOnlyList<Type> list, int ix,
ref int usedGenericArgumentCounter)
{
var type = list[ix];
if (TypeToFriendlyName.TryGetValue(type, out string fname))
{
sb.Write(fname);
return;
}
if (type.IsGenericParameter)
{
sb.Write(type.Name);
return;
}
if (type.IsArray)
{
ToCSharpNameEntry2(sb, type.GetElementType());
sb.Write("[]");
return;
}
if (type.IsGenericType)
{
var innermostType = list[list.Count - 1];
var args = list[list.Count - 1].GenericTypeArguments;
if (!type.IsConstructedGenericType)
{
if (innermostType.IsConstructedGenericType)
{
var sname = GetSname(type);
sb.Write(sname);
sb.Write("<");
ToCSharpNameEntry2(sb, args[usedGenericArgumentCounter++]);
var loopCounter = ((TypeInfo) type).GenericTypeParameters.Length;
while (0 < --loopCounter)
{
sb.Write(",");
ToCSharpNameEntry2(sb, args[usedGenericArgumentCounter++]);
}
sb.Write(">");
return;
}
throw new NotImplementedException();
}
if (typeof(Nullable<>) == type.GetGenericTypeDefinition())
{
ToCSharpNameEntry2(sb, args[0]);
sb.Write("?");
return;
}
var cname = GetSname(type);
sb.Write(cname);
sb.Write("<");
ToCSharpNameEntry2(sb, args[usedGenericArgumentCounter++]);
while (usedGenericArgumentCounter < args.Length)
{
sb.Write(",");
ToCSharpNameEntry2(sb, args[usedGenericArgumentCounter++]);
}
sb.Write(">");
return;
}
if (type.IsPointer)
{
ToCSharpNameEntry2(sb, type);
sb.Write("*");
return;
}
sb.Write(type.Name);
}
private static string GetSname(Type type)
{
var name = type.Name;
return name.Substring(0, name.IndexOf('`'));
}
private static List<Type> GetContainingTypeList(Type type)
{
var list = new List<Type> {type};
var t = type;
while (t.IsNested)
{
t = t.DeclaringType;
list.Insert(0, t);
}
return list;
}
private static void ToCSharpNameEntry(StringBuilder sb, Type type)
{
var genericTypeArguments = type.GenericTypeArguments;
var usedGenericTypeCounter = 0;
ToCSharpNameRecursive(sb, type, genericTypeArguments, ref usedGenericTypeCounter);
}
private static void ToCSharpNameRecursive(StringBuilder sb, Type type, IReadOnlyList<Type> genericTypeArguments,
ref int genericTypesCounter)
{
if (TypeToFriendlyName.TryGetValue(type, out string res))
{
sb.Append(res);
return;
}
HandleNonPriminiveTypes(sb, type, genericTypeArguments, ref genericTypesCounter);
}
private static void HandleNonPriminiveTypes(StringBuilder sb, Type type, IReadOnlyList<Type> typeGenericTypeArguments,
ref int genericTypesCounter)
{
var list = new List<Type>();
var t = type;
list.Add(t);
while (t.IsNested)
{
t = t.DeclaringType;
list.Add(t);
}
list.Reverse();
foreach (var type1 in list)
{
HandleNestedLevel(sb, type1, typeGenericTypeArguments, ref genericTypesCounter);
sb.Append(".");
}
sb.Length -= 1;
}
private static void HandleNestedLevel(StringBuilder sb, Type type, IReadOnlyList<Type> typeGenericTypeArguments,
ref int genericTypesCounter)
{
var name = type.Name;
if (type.IsGenericType)
{
var info = type.GetTypeInfo();
var def = info.GetGenericTypeDefinition();
var psLength = info.IsConstructedGenericType
? info.GenericTypeArguments.Length
: info.GenericTypeParameters.Length;
if (typeof(Nullable<>) == def)
{
var type1 = typeGenericTypeArguments[genericTypesCounter++];
ToCSharpNameEntry(sb, type1);
sb.Append("?");
return;
}
var n = name.Substring(0, name.IndexOf("`", StringComparison.InvariantCultureIgnoreCase));
sb.Append(n);
sb.Append("<");
for (var i = 0; i < psLength; i++)
{
ToCSharpNameEntry(sb, typeGenericTypeArguments[genericTypesCounter++]);
sb.Append(",");
}
sb.Length -= 1;
sb.Append(">");
return;
}
if (type.IsArray)
{
var type1 = type.GetElementType();
ToCSharpNameEntry(sb, type1);
sb.Append("[]");
return;
}
sb.Append(name);
}
}
我在编写要由Roslyn编译的源文本时使用扩展方法
在不分割字符串的情况下,没有方法。