C#: switch, is, type, typeof(), GetType()

Hi, programmers!

This one works pretty well:

	if (Collided[Collided.Count - 1] is Human)
		Debug.Log("WORKS!");

And this one doesn’t even want to compile:

	switch (Collided[Collided.Count - 1].GetType())
	{
		case typeof(Human):
			Debug.Log("WORKS!");
			break;
	}

What am I doing wrong?

Thanks.

I think you’re probably taking the wrong approach to your problem. You’re likely trying to implement polymorphism without knowing it. You’d be better off giving human some sort of “HandleCollision” virtual method, and doing something like:

var human = obj as Human;
if (human != null) human.HandleCollision();

Alternatively, you could create an interface with a “HandleCollision” method and anything that should respond to collisions can implement that interface, and the code above would simply be changed to:

var collider = obj as MyInterface;
if (collider != null) collider.HandleCollision();

You can not use a type as a case in a switch statement. However you could(COULD) use the string version of the type instead and that would work fine.

    switch (Collided[Collided.Count - 1].GetType().ToString())
    {
        case "Human":

            Debug.Log("WORKS!");

            break;
    }
}
1 Like

I converted some code of mine from Unityscript to C#, and that’s one of the downsides. I replaced the type switches with a chain of if…else.

Please notice that it’s not the same to use “obj.GetType() == typeof(obj)” instead of “is”. Read this article to understand the differences: http://blogs.msdn.com/b/vancem/archive/2006/10/01/779503.aspx

tmills, you’re right!

Thank you, guys. It helped.

Hey all I know this is an old thread but I wanted to shout out C# 7 added pattern matching which making switching on types much easier. Here is a quick code snippet I took from this blog which explains how to C# switch on types.

switch (vehicle)
{
    case Car car:
        WriteLine("Car!");
        break;
    case Truck truck:
        WriteLine("Truck!");
        break;
    case null:
        throw new ArgumentNullException();
        break;
    default:
        // Anything other than Car, Truck or null
        throw new UnknownVehicleException();
        break;
}

Cheers!

10 Likes

Though Unity 2019.3 is supposed to support C# 7.3 I cannot switch on types, I tried this:

            switch (GetType())
            {
                case MonoBehaviour mb:
                    break;
                case typeof(MonoBehaviour) mobe:
                    break;
            }

Because none of your two code examples make sense. GetType returns a System.Type object that describes the type of whatever you call GetType on. However that System.Type object has nothing to do with your specific instance of the type. It’s part of the reflection and type system of C#. You try to use the new switch statements to auto-cast a reference which however is not a reference to your instance but just the System.Type object.

Since you just called GetType(), you essentially did call this.GetType(). If you want to check the type of this you would have to do

switch (this)
{
    case MonoBehaviour mb:
        break;
}

Thanks! That explains why it wouldn’t work. Use the object, not the type, even though you want to switch on “Type”. Kind of confusing. :slight_smile:

That means I have to stick to this because all I have at this point is the System.Type:

        private static string GetConvertMethodForType(System.Type type)
        {
            switch (type.Name)
            {
                case nameof(System.Single):
                    return "System.Convert.ToSingle";
                case nameof(System.Byte):
                    return "System.Convert.ToByte";
                case nameof(System.Int16):
                    return "System.Convert.ToShort";
                case nameof(System.Int32):
                    return "System.Convert.ToInt32";
                case nameof(System.Int64):
                    return "System.Convert.ToInt64";
                case nameof(System.Boolean):
                    return "System.Convert.ToBoolean";
                case nameof(System.String):
                    return "System.Convert.ToString";
                case null:
                default:
                    return string.Empty;
            }
        }
2 Likes

This is one of those unfixable methods, because either a) it’s the only way, or b) if you have a method like this the entire concept behind why this method is needed is already broken. B is much more likely.

Put another way, trying to improve this function is like trying to improve the SmackSelfInFace() method. It might be the best way to smack yourself in the face but why would you do that?

What’s calling GetConvertMethodForType?

While string comparisons may be necessary or the only way in some cases, note that a switch case in the end is translated to some other form of branching / analysis wrapping code. For simple ordinal types with no gaps, a switch case usually creates a jump table where the input is directly used to jump to a certain code fragment. When the cases do not show good patterns that can be exploited by the compiler / Jitter, if you only have a few cases it would resort to an if-else chain. If there are more cases it almost always creates a look up dictionary.

In this case I would also recommend to manually use a dictionary, especially when the method is used a lot. In a dictionary you can use System.Type objects as keys since they are also just object references.

    public static Dictionary<System.Type, string> m_ConvertMethods = new Dictionary<System.Type, string>(){
        {typeof(System.Single), "System.Convert.ToSingle"},
        {typeof(System.Byte), "System.Convert.ToByte"},
        {typeof(System.Int16), "System.Convert.ToShort"},
        {typeof(System.Int32), "System.Convert.ToInt32"},
        {typeof(System.Int64), "System.Convert.ToInt64"},
        {typeof(System.Boolean), "System.Convert.ToBoolean"},
        {typeof(System.String), "System.Convert.ToString"},
    };
  
    private static string GetConvertMethodForType(System.Type type)
    {
        if (m_ConvertMethods.TryGetValue(type, out string methodName))
            return methodName;
         return null;
    }
1 Like

Thanks for converting this into a dictionary! That makes more sense. :slight_smile:
Also new to me: declaring out parameters within the parameter list. What a blessing! This also works nicely with “var” btw!

I use this formerly-switch code to generate a class whose constructor only receives a List imported from a spreadsheet file, hence I have to look up the proper Convert.ToSomething method since casting won’t do (casting != unboxing). It’s one of those unconventional cases where you generate C# scripts that import data from another text file and need to figure out how to convert that to int, float, etc.

This is used in the Spreadsheet Database 4U tool (SSDB) I’m developing.

Yes, that’s actually a relatively new feature in C# (can’t remember the C# version, I think 7?)

Not sure what you actually want to do, but you can change / convert an object to another type by using System.Convert.ChangeType. The return value is still of type Object but the actual type is converted. Maybe that’s what you actually want to do? You can do almost anything with reflection in a dynamic way. Though some things get exponentially more complex.

Correct, C# 7 (actually 7.1, seems like there never was a public 7.0). That was August 2017 and a year later I stopped programming C# until now. I think first Unity version to support 7 was 2019.something. 2019.4 is what I’m working with.

I do need to use the individual ConvertTo since the object has to be unboxed and is then assigned to a field with the specified type. As in:

int i = Convert.ToInt32(obj);