简体   繁体   中英

Why typeof(int).ToString() is not constant?

I'm trying to do this:

const string intType = typeof(int).ToString();
switch (typeof(MyT).ToString())
{
    case intType:
    {
        return "int";
        break;
    }
    ...
}

But compiler says:

error CS0133: The expression being assigned to 'intType' must be constant

As I know, typeof operator works at compile-time. So, what's wrong?

As I know, typeof operator works at compile-time.

You don't know that because knowledge has to be true . Where did you get the idea that typeof is executed at compile time? It produces a non-constant object. And then there is no guarantee that ToString doesn't produce a different string every time it runs, so it cannot be treated as a constant either.

So, what's wrong?

You're reasoning from a false belief.

The C# specification clearly describes the conditions that must be met for an expression to be a compile-time constant. Those conditions include the expression not containing any typeof operator or method call.

But there are far bigger problems here. I assume that MyT is a generic type parameter, which means you are attempting to switch on the value of a generic type parameter. That is almost always the wrong thing to do.

What are you really trying to do? What problem are you really trying to solve? Because this code you've shown so far indicates that you're going down an unproductive path to solve whatever the real problem is.

The only way to compare type MyT with known types is by checking their Type objects for equality. This can be done as follows:

if (typeof(MyT) == typeof(int)) return "int";
if (typeof(MyT) == typeof(decimal)) return "decimal";
// etc...

You cannot use this approach in a switch because (at the moment) a switch requires that the item being checked is of a simple type:

switch (typeof(T)) // Compile error: "switch expression or case label must be a bool,
                   // char, string, integral, enum, or corresponding nullable type"
{
    case typeof(int): return "int";
    case typeof(decimal): return "decimal";
    // ...
}

Also, as others already said, checking types in this way almost always means that your approach can be improved by applying different object oriented principles.

Eg instead of MyMethod<MyT>(MyT item) with type checks for MyT , consider making MyMethod(int item) , MyMethod(decimal item) etc.

I think, it is quite obvious, what he wants to achieve:

He wants to check for type equality in a switch-case instead of via if-elseif . And to be honest, why not? But how can he achieve this?

  1. First option: Wait for C# 7.0 . Yeah, shit like this is possible in the future!

  2. Second option: Use strings. But the case strings need to be constant. So what about the wonderful nameof ?

I just tried this "beauty" and it works, so maybe this solves your problem:

switch (typeof(Int32).Name)
{
    case nameof(Int32):
         Console.WriteLine("It's an Int32!");
         break;
    case nameof(Double):
         Console.WriteLine("It's a Double");
         break;
 }

If you are just trying to get a string describing the type of object, you just need to call .GetType() instead.

For example, the following is a small function that will return the string name of the object type.

 static string GetTypeString(object obj)
 {
      return obj.GetType().FullName;
 }

This will return to the full path to the object. In int's case, it will return System.Int32. If you only want the Int32 part, use GetType().Name instead.

Also, you don't need to have a break; in a switch if you have a return;

If you have specific code that needs to be run for some types, or a specific string you want to return, you can use a string on the values returned by the above. For example:

   static string GetSimpleType(object obj)
    {
        var stringRepresentation = GetTypeString(obj);
        switch (stringRepresentation)
        {
            case "System.Int64":
            case "System.Int32":
                return "int";

            default:
                return stringRepresentation;
        }
    }

default is a catch all in switch statements for everything that does not have a case. Think of it like an else.

In the above example, we return the same value for int, Int32, and Int64. Case labels can fall through to other case labels if they are empty.

You can find all the values you need to write a switch for by running a simple script, and hard code the string values since they will always be the same for the same types. If the string is different, then the type is different.

Finally, if you are comparing types, if and if else works better:

        static string GetSimpleType(object obj)
        {
           if (obj.GetType() == typeof(int))
           {
               return "int"; 
           }

            return obj.GetType().ToString();
        }

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