Author avatar

Dániel Szabó

It Is What It Is and As It Is: Using the Is and As Operators in C#

Dániel Szabó

  • Jan 9, 2020
  • 8 Min read
  • 154 Views
  • Jan 9, 2020
  • 8 Min read
  • 154 Views
Languages Frameworks and Tools
C#

Introduction

Two of the most common tasks a C# developer faces are type-casting and compatibility checking. Type-casting comes in handy when we would like to convert an object of a certain type to another object of the same type. Compatibility checking is a facility in C# to support the casting operation. The support for this comes in form of two operators, one called as and the other called is. This guide will clarify the difference between those two and help you incorporate them into your applications as effectively as possible.

The Challenge

Let's take the following code as an example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;

namespace asitis
{
    public class Student
    {
    }
    class itisas
    {
        static void Main(string[] args)
        {
            Student s = new Student();
            object c = s;
            string r = (string)c;
            Console.ReadKey(); ;
        }
    }
}
csharp

We have an empty class called Student, and if we wrote this code in an IDE like Visual Studio, we wouldn't get any warning of the incoming exception that occurs when we compile and run the app. This type of error occurs at runtime.

1
System.InvalidCastException: 'Unable to cast object of type 'asitis.Student' to type 'System.String'.'
bash

There is no indication to the compiler that would prevent the compilation because we tried to cast one type of an object into an incompatible type.

What can we do about it? The first and most common approach is the try{}catch{} block. Most developers' first attempt would be to wrap potentially critical code and handle the exception as it occurs.

That would look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;

namespace asitis
{
    public class Student
    {
    }
    class itisas
    {
        static void Main(string[] args)
        {
            Student s = new Student();
            object c = s;
            try
                { string r = (string)c; }
            catch
                { Console.WriteLine($"Could not cast {nameof(c)} as string!"); }
            
            Console.ReadKey(); ;
        }
    }
}
csharp

After running the code, we won't get an exception like before, but we will get the following output:

1
Could not cast c as string!
csharp

This solution is perfectly viable, however, in a big application this would make the application more unstable and harder to read or maintain for the developers.

There must be a better way!

Is Operator

The is operator will check if the result of the expression is compatible with a given type by simply testing an expression against a pattern. It is sometimes called the operator of type testing, and it will check whether the runtime type of an expression's result is compatible with a given type. The test against patterns came to C# as a feature with version 7.0.

Let's demonstrate the functionality with a small example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;

namespace asitis
{
    public class Student
    { }
    public class Teacher
    { }
    class itisas
    {
        static void testClass(object o)
        {
            if(o is Student)
                { Console.WriteLine($"The instance: {nameof(o)} we recieved as argument is from Student class!"); }
            else if(o is Teacher)
                { Console.WriteLine($"The instance: {nameof(o)} we recieved as argument is from Teacher class!"); }
            else
                { Console.WriteLine($"The instance: {nameof(o)} we recieved as argument is from neither Teacher nor Student class!"); }
        }
        static void Main(string[] args)
        {
            Student s = new Student();
            Teacher t = new Teacher();
            int i = 0;
            testClass(s);
            testClass(t);
            testClass(i);
            Console.ReadKey(); ;
        }
    }
}
csharp

The output of the code is pretty self explanatory.

1
2
3
The instance: o we recieved as argument is from Student class!
The instance: o we recieved as argument is from Teacher class!
The instance: o we recieved as argument is from neither Teacher nor Student class!
bash

We basically have two skeleton classes that allow us the create different instances. In our main class we have the function testClass, which takes an arbitrary object and prints out to the console whether it's a Student, a Teacher, or neither.

As Operator

The as operator is used to perform conversions between compatible types. It has a very similar role to the is operator, however, it works differently under the hood.

Let's reuse our previous code to demonstrate the functionality.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;

namespace asitis
{
    public class Student
    {
    }
    public class Teacher
    {

    }
    class itisas
    {
        static void Main(string[] args)
        {
            object[] MyObjects = new object[4];
            MyObjects[0] = new Student();
            MyObjects[1] = new Teacher();
            MyObjects[2] = "Student";
            MyObjects[3] = "Teacher";
            for(int i = 0; i < 4; i++)
            {
                string s = MyObjects[i] as string;
                Console.Write($"Inspecting element: {MyObjects[i]}");
                if (s == null)
                    { Console.Write(" ->> Incompatible type"); }
                else
                    { Console.Write(" ->> Compatible type"); }
                Console.WriteLine(", with string!");
            }
            Console.ReadKey(); ;
        }
    }
}
csharp

We have our two classes from before, and we create a list of objects. This is important because the object type allows you to create a list that can hold different types of objects. Then we fill it up with a teacher, a student, and two strings. Then we iterate over the array, checking which one of them is compatible with the string type with the help of the as operator. Note that it does not throw an exception when we have an incompatible type, we just simply don't have any value associated with the s variable, which evaluates to null.

The output of the execution looks like this.

1
2
3
4
Inspecting element: asitis.Student ->> Incompatible type, with string!
Inspecting element: asitis.Teacher ->> Incompatible type, with string!
Inspecting element: Student ->> Compatible type, with string!
Inspecting element: Teacher ->> Compatible type, with string!
bash

Differences Between As and Is

The is operator is used to check if the run-time type of an object is compatible with the given type or not, whereas the as operator is used to perform conversion between compatible reference types or nullable types.

The is operator is of Boolean type, whereas the as operator is not.

The is operator returns true if the given object is of the same type, whereas the as operator returns the object when they are compatible with the given type.

The is operator returns false if the given object is not of the same type, whereas the as operator returns null if the conversion is not possible.

The is operator is used for only reference, boxing, and unboxing conversions, whereas the as operator is used only for nullable, reference, and boxing conversions.

Conclusion

In this article, you became familiar with type-casting and compatibility checking in the form of two operators. These operators incorporate greater flexibility into your applications and allow you to develop more robust programs. I hope this was worth your while, and you found what you were looking for. Thanks for reading!

1