Difference between the use of typeof and is

Asked

Viewed 5,198 times

42

In C# when I need to check if a variable is of a certain type, I usually use the operator is:

if(qualquerVariavel is int)
    Console.Write("A variável é int");

I know it is also possible to check the type of a variable in other ways, one of them is using typeof:

if(qualquerVariavel.GetType() == typeof(int))
    Console.WriteLine("A variável é int");

What is the difference between these two operators? There are others who "do the same thing", but with a small difference?

3 answers

48


  • is checks the entire inheritance structure of the object;
  • typeof() returns the exact type of the object.

For a better illustration:

class Animal { } 
class Cachorro : Animal { }

var a = new Cachorro();

Console.WriteLine(a.GetType() == typeof(Animal)) // false 
Console.WriteLine(a is Animal)                   // true 
Console.WriteLine(a.GetType() == typeof(Cachorro))    // true

15

An important detail is that if the variable is null, the operator is always returns false.

string s = null;

s is string == false
s is object == false
s is int    == false

Needless to say, GetType does not work with null.

At first glance, it may seem like inconsistent behavior. But Eric Lippert (former member of the C#language design committee) explains why here: What the meaning of is is

The Fact that a null Reference may be Assigned to a string variable does not make the null Reference a string, any more than the Fact that your driveway can be Empty Means that an Empty driveway contains a Honda Civic. The is Operator does not Answer the Question "can I assign this Reference to a variable of the Given type?" It Answers the Question "is this Reference a legitimate Reference to an Object of the Given type?" , and null is not a legitimate Reference.

Or

The fact that a null reference can be assigned to a variable string does not make the null reference a string; like the fact that a garage may be empty, it does not mean that an empty garage contains a Honda Civic. The operator is does not answer the question: "Can I assign this reference to a variable of this type?". He answers the question "Is this reference a legitimate reference to an object of this kind?" and null is not a legitimate reference.

Consequently, we can also observe that a non-zero reference of the type Nullable<T> is also a valid reference of type T, and vice versa. Exemplifying:

int i = 1;

i is int  == true
i is int? == true

int? ni = 1;

ni is int  == true
ni is int? == true
  • 2

    It doesn’t work because it obviously throws an exception hehe

9

The existing answers already tell the difference. But C# 7 gave a new function for the is.

When do you need to check the type of the object? When you don’t know the exact type you are getting.

What do you do to use this object with the type you checked? It probably does a cast for the type and then have access to the members available in this type. If you do not need to access these members you do not have to do the cast, and then you don’t have to check what kind it is.

As in most cases the cast is the desired C# 7 allows this to be done automatically.

using static System.Console;
using System;

public class Program {
    public static void Main() {
        Teste(DateTime.Now);
        WriteLine();
        Teste("ok");
    }

    public static void Teste(object qualquerVariavel) {
        if (qualquerVariavel is DateTime x) WriteLine($"A variável é DateTime e seu valor é {x.DayOfWeek}");
        if (qualquerVariavel is DateTime) WriteLine($"A variável é DateTime e seu valor é {((DateTime)qualquerVariavel).DayOfWeek}");
        if (qualquerVariavel is DateTime) //WriteLine($"A variável é DateTime e seu valor é {qualquerVariavel.DayOfWeek}"); //isto não compila
        if (qualquerVariavel is "ok") WriteLine($"A variável é string e vale ok");
        switch (qualquerVariavel) {
            case null:
                WriteLine("nulo");
                break;
            case int i:
                WriteLine(i);
                break;
            case string s:
                WriteLine(s);
                break;
            case DateTime d:
                WriteLine(d.DayOfWeek);
                break;
        }
    }
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

Note that the variable is declared inside the if or case but it has scope of method, so it cannot use the same name on each one. This is because it is not inside the block of the if, the condition itself does not create new scope.

The use of switch may appear not to be using the is, but as the == is implicit in it, the is is also there even if you don’t see.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.