简体   繁体   中英

GetType return Int instead of System.Int32

GetType().ToString() returns the FullName of the object. I want the name that you usually use to instantiate that object, ie, int instead of Int32. Is there a way to do this?

C# has a number of 'types' that are actually keyword aliases to .NET CLR Type s. In this case, int is a C# alias for System.Int32 , but the same is true of other C# types like string which is an alias to System.String .

This means that when you get under the hood with reflection and start looking at the CLR Type objects you won't find int , string or any of the other C# type aliases because .NET and the CLR don't know about them... and nor should they.

If you want to translate from the CLR type to a C# alias you'll have to do it yourself via lookup. Something like this:

// This is the set of types from the C# keyword list.
static Dictionary<Type, string> _typeAlias = new Dictionary<Type, string>
{
    { typeof(bool), "bool" },
    { typeof(byte), "byte" },
    { typeof(char), "char" },
    { typeof(decimal), "decimal" },
    { typeof(double), "double" },
    { typeof(float), "float" },
    { typeof(int), "int" },
    { typeof(long), "long" },
    { typeof(object), "object" },
    { typeof(sbyte), "sbyte" },
    { typeof(short), "short" },
    { typeof(string), "string" },
    { typeof(uint), "uint" },
    { typeof(ulong), "ulong" },
    // Yes, this is an odd one.  Technically it's a type though.
    { typeof(void), "void" }
};

static string TypeNameOrAlias(Type type)
{
    // Lookup alias for type
    if (_typeAlias.TryGetValue(type, out string alias))
        return alias;

    // Default to CLR type name
    return type.Name;
}

For simple types that will work fine. Generics, arrays and Nullable take a bit more work. Arrays and Nullable values are handled recursively like this:

static string TypeNameOrAlias(Type type)
{
    // Handle nullable value types
    var nullbase = Nullable.GetUnderlyingType(type);
    if (nullbase != null)
        return TypeNameOrAlias(nullbase) + "?";

    // Handle arrays
    if (type.BaseType == typeof(System.Array))
        return TypeNameOrAlias(type.GetElementType()) + "[]";

    // Lookup alias for type
    if (_typeAlias.TryGetValue(type, out string alias))
        return alias;

    // Default to CLR type name
    return type.Name;
}

This will handle things like:

Console.WriteLine(TypeNameOrAlias(typeof(int?[][])));

Generics, if you need them, are a bit more involved basically the same process. Scan through the generic parameter list and run the types recursively through the process.


Nested Types

When you run TypeNameOrAlias on a nested type the result is only the name of the specific type, not the full path you'd need to specify to use it from outside the type that declares it:

public class Outer
{
    public class Inner
    {
    }
}
// TypeNameOrAlias(typeof(Outer.Inner)) == "Inner"

This resolves the issue:

static string GetTypeName(Type type)
{
    string name = TypeNameOrAlias(type);
    if (type.DeclaringType is Type dec)
    {
        return $"{GetTypeName(dec)}.{name}";
    }
    return name;
}
// GetTypeName(typeof(Outer.Inner)) == "Outer.Inner"

Generics

Generics in the .NET type system are interesting. It's relatively easy to handle things like List<int> or Dictionary<int, string> or similar. Insert this at the top of TypeNameOrAlias :

    // Handle generic types
    if (type.IsGenericType)
    {
        string name = type.Name.Split('`').FirstOrDefault();
        IEnumerable<string> parms = 
            type.GetGenericArguments()
            .Select(a => type.IsConstructedGenericType ? TypeNameOrAlias(a) : a.Name);
        return $"{name}<{string.Join(",", parms)}>";
    }

Now you'll get correct results for things like TypeNameOrAlias(typeof(Dictionary<int, string>)) and so on. It also deals with generic type definitions: TypeNameOrAlias(typeof(Dictionary<,>)) will return Dictionary<TKey,TValue> .

Where things get difficult is when you nest classes inside generics. Try GetTypeName(typeof(Dictionary<int, string>.KeyCollection)) for an interesting result.

GetType().ToString().FromDotNetTypeToCSharpType();

Using the extension method below. I came up with something similar for some templating I was doing in c# using the following Microsoft reference:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/built-in-types-table

Optionally, a boolean whether the type is nullable can be passed in for the shortcut nullable syntax.

    /// <summary>Converts a .Net type name to a C# type name. It will remove the "System." namespace, if present,</summary>
    public static string FromDotNetTypeToCSharpType(this string dotNetTypeName, bool isNull = false)
    {
        string cstype = "";
        string nullable = isNull ? "?" : "";
        string prefix = "System.";
        string typeName = dotNetTypeName.StartsWith(prefix) ? dotNetTypeName.Remove(0, prefix.Length) : dotNetTypeName;

        switch (typeName)
        {
            case "Boolean": cstype = "bool"; break;
            case "Byte":    cstype = "byte"; break;
            case "SByte":   cstype = "sbyte"; break;
            case "Char":    cstype = "char"; break;
            case "Decimal": cstype = "decimal"; break;
            case "Double":  cstype = "double"; break;
            case "Single":  cstype = "float"; break;
            case "Int32":   cstype = "int"; break;
            case "UInt32":  cstype = "uint"; break;
            case "Int64":   cstype = "long"; break;
            case "UInt64":  cstype = "ulong"; break;
            case "Object":  cstype = "object"; break;
            case "Int16":   cstype = "short"; break;
            case "UInt16":  cstype = "ushort"; break;
            case "String":  cstype = "string"; break;

            default: cstype = typeName; break; // do nothing
        }
        return $"{cstype}{nullable}";

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM