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.
Let's take the following code as an example.
1using System;
2
3namespace asitis
4{
5 public class Student
6 {
7 }
8 class itisas
9 {
10 static void Main(string[] args)
11 {
12 Student s = new Student();
13 object c = s;
14 string r = (string)c;
15 Console.ReadKey(); ;
16 }
17 }
18}
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.
1System.InvalidCastException: 'Unable to cast object of type 'asitis.Student' to type 'System.String'.'
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:
1using System;
2
3namespace asitis
4{
5 public class Student
6 {
7 }
8 class itisas
9 {
10 static void Main(string[] args)
11 {
12 Student s = new Student();
13 object c = s;
14 try
15 { string r = (string)c; }
16 catch
17 { Console.WriteLine($"Could not cast {nameof(c)} as string!"); }
18
19 Console.ReadKey(); ;
20 }
21 }
22}
After running the code, we won't get an exception like before, but we will get the following output:
1Could not cast c as string!
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!
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.
1using System;
2
3namespace asitis
4{
5 public class Student
6 { }
7 public class Teacher
8 { }
9 class itisas
10 {
11 static void testClass(object o)
12 {
13 if(o is Student)
14 { Console.WriteLine($"The instance: {nameof(o)} we recieved as argument is from Student class!"); }
15 else if(o is Teacher)
16 { Console.WriteLine($"The instance: {nameof(o)} we recieved as argument is from Teacher class!"); }
17 else
18 { Console.WriteLine($"The instance: {nameof(o)} we recieved as argument is from neither Teacher nor Student class!"); }
19 }
20 static void Main(string[] args)
21 {
22 Student s = new Student();
23 Teacher t = new Teacher();
24 int i = 0;
25 testClass(s);
26 testClass(t);
27 testClass(i);
28 Console.ReadKey(); ;
29 }
30 }
31}
The output of the code is pretty self explanatory.
1The instance: o we recieved as argument is from Student class!
2The instance: o we recieved as argument is from Teacher class!
3The instance: o we recieved as argument is from neither Teacher nor Student class!
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.
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.
1using System;
2
3namespace asitis
4{
5 public class Student
6 {
7 }
8 public class Teacher
9 {
10
11 }
12 class itisas
13 {
14 static void Main(string[] args)
15 {
16 object[] MyObjects = new object[4];
17 MyObjects[0] = new Student();
18 MyObjects[1] = new Teacher();
19 MyObjects[2] = "Student";
20 MyObjects[3] = "Teacher";
21 for(int i = 0; i < 4; i++)
22 {
23 string s = MyObjects[i] as string;
24 Console.Write($"Inspecting element: {MyObjects[i]}");
25 if (s == null)
26 { Console.Write(" ->> Incompatible type"); }
27 else
28 { Console.Write(" ->> Compatible type"); }
29 Console.WriteLine(", with string!");
30 }
31 Console.ReadKey(); ;
32 }
33 }
34}
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.
1Inspecting element: asitis.Student ->> Incompatible type, with string!
2Inspecting element: asitis.Teacher ->> Incompatible type, with string!
3Inspecting element: Student ->> Compatible type, with string!
4Inspecting element: Teacher ->> Compatible type, with string!
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.
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!