我有以下代码:

return "[Inserted new " + typeof(T).ToString() + "]";

But

 typeof(T).ToString()

返回包括命名空间在内的全名

是否有方法只获取类名(没有任何名称空间限定符?)


当前回答

利用(类型属性)

 Name   Gets the name of the current member. (Inherited from MemberInfo.)
 Example : typeof(T).Name;

其他回答

尝试获取泛型类型的类型参数:

public static string CSharpName(this Type type)
{
    var sb = new StringBuilder();
    var name = type.Name;
    if (!type.IsGenericType) return name;
    sb.Append(name.Substring(0, name.IndexOf('`')));
    sb.Append("<");
    sb.Append(string.Join(", ", type.GetGenericArguments()
                                    .Select(t => t.CSharpName())));
    sb.Append(">");
    return sb.ToString();
}

也许不是最好的解决方案(由于递归),但它是有效的。输出如下:

Dictionary<String, Object>

在c# 6.0(包括)之后,你可以使用nameof表达式:

using Stuff = Some.Cool.Functionality  
class C {  
    static int Method1 (string x, int y) {}  
    static int Method1 (string x, string y) {}  
    int Method2 (int z) {}  
    string f<T>() => nameof(T);  
}  

var c = new C()  

nameof(C) -> "C"  
nameof(C.Method1) -> "Method1"   
nameof(C.Method2) -> "Method2"  
nameof(c.Method1) -> "Method1"   
nameof(c.Method2) -> "Method2"  
nameof(z) -> "z" // inside of Method2 ok, inside Method1 is a compiler error  
nameof(Stuff) = "Stuff"  
nameof(T) -> "T" // works inside of method but not in attributes on the method  
nameof(f) -> “f”  
nameof(f<T>) -> syntax error  
nameof(f<>) -> syntax error  
nameof(Method2()) -> error “This expression does not have a name”  

注意!nameof不能获取底层对象的运行时类型,它只是编译时参数。如果一个方法接受一个IEnumerable对象,那么nameof简单地返回“IEnumerable”,而实际的对象可以是“List”。

下面的代码块在处理嵌套时生成类型名:

数组(T []) 泛型参数(即IEnumerable<T>)

此外,如果当前类型有可用的类型别名,它会尝试使用类型别名,这意味着会处理以下情况:

类型别名关键字(即System。字符串=> 可空类型别名(Nullable<T> => T?) ValueTuple别名,包括TRest嵌套(ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8, T9> => (T1, T2, T3, T4, T5, T6, T7, T8, T9))

代码如下:

public static class TypeExtensions
{
    public static string GetFinalName(this Type type)
    {
        return GetFinalNameGenerator(type);
    }

    private static string GetFinalNameGenerator(Type type, bool parentIsTRest = false)
    {
        if (type.IsSZArray)
            return $"{GetFinalNameGenerator(type.GetElementType())}[]";
        if (!type.IsGenericType)
            return TypeToAliasIfPossible(type);
        if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
            return $"{GetGenericArgumentsDisplay(type)}?";
        if (parentIsTRest || IsTupleAlias(type))
            return ValueTupleToAlias(type, parentIsTRest);
        return $"{type.Name[new Range(0, type.Name.IndexOf('`'))]}<{GetGenericArgumentsDisplay(type)}>";
    }

    private static string TypeToAliasIfPossible(Type type)
    {
        var typeAliasDict = new Dictionary<Type, string>
        {
            [typeof(bool)] = "bool",
            [typeof(byte)] = "byte",
            [typeof(sbyte)] = "sbyte",
            [typeof(short)] = "short",
            [typeof(ushort)] = "ushort",
            [typeof(int)] = "int",
            [typeof(uint)] = "uint",
            [typeof(long)] = "long",
            [typeof(ulong)] = "ulong",
            [typeof(float)] = "float",
            [typeof(double)] = "double",
            [typeof(decimal)] = "decimal",
            [typeof(char)] = "char",
            [typeof(string)] = "string",
            [typeof(object)] = "object",
            [typeof(void)] = "void"
        };
        return typeAliasDict.GetValueOrDefault(type) ?? type.Name;
    }

    private static string GetGenericArgumentsDisplay(Type type)
    {
        return GetDisplay(type.GetGenericArguments());
    }

    private static string GetDisplay(IEnumerable<Type> genericArguments)
    {
        return string.Join(", ", genericArguments.Select(genericArgument => GetFinalNameGenerator(genericArgument)));
    }

    private static bool IsTupleAlias(Type type, bool parentIsTRest = false)
    {
        if (parentIsTRest && !type.IsGenericType)
            return false;

        var genericTypeDefinition = type.GetGenericTypeDefinition();
        return genericTypeDefinition == typeof(ValueTuple<,>)
               || genericTypeDefinition == typeof(ValueTuple<,,>)
               || genericTypeDefinition == typeof(ValueTuple<,,,>)
               || genericTypeDefinition == typeof(ValueTuple<,,,,>)
               || genericTypeDefinition == typeof(ValueTuple<,,,,,>)
               || genericTypeDefinition == typeof(ValueTuple<,,,,,,>)
               || (parentIsTRest && genericTypeDefinition == typeof(ValueTuple<>))
               || (genericTypeDefinition == typeof(ValueTuple<,,,,,,,>) && IsTupleAlias(type.GetGenericArguments()[^1], true));
    }

    private static string ValueTupleToAlias(Type type, bool parentIsTRest)
    {
        var genericArguments = type.GetGenericArguments();
        var valueTupleText = type.GetGenericTypeDefinition() != typeof(ValueTuple<,,,,,,,>)
            ? GetDisplay(genericArguments)
            : $"{GetDisplay(genericArguments[new Range(0, ^1)])}, {GetFinalNameGenerator(genericArguments[^1], true)}";
        return parentIsTRest
            ? valueTupleText
            : $"({valueTupleText})";
    }
}

用法很简单:

Console.WriteLine(typeof(Dictionary<string, IEnumerable<int?[][]>>).GetFinalName());
// Outputs: Dictionary<string, IEnumerable<int?[][]>>

如果你发现这个解决方案没有涵盖的任何边缘情况,请回复这篇文章,我会尝试更新答案。

typeof(T).Name // class name, no namespace
typeof(T).FullName // namespace and class name
typeof(T).Namespace // namespace, no class name

利用(类型属性)

 Name   Gets the name of the current member. (Inherited from MemberInfo.)
 Example : typeof(T).Name;