Page 1 of 1

The 'is' and 'as' Keywords Casting using these keywords

#1 CodingSup3rnatur@l-360  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 991
  • View blog
  • Posts: 971
  • Joined: 30-September 10

Posted 25 October 2010 - 03:13 PM

*
POPULAR

The ‘as’ and ‘is’ keywords Tutorial

Hello everybody and welcome to my tutorial!

I remember when I first started learning c#, the distinction between the ‘as’ and ‘is’ keywords was quite blurry. Also, it isn't a particuarly difficult topic, but it is one that a lot of beginners don't fully understand or aren't even aware of. Therefore, I decided to do a mini tutorial just to outline the uses and differences of each.


The ‘is’ keyword

The best way to think about the ‘is’ keyword is that it tests whether or not an object can be cast to another object. That is all it is; a test for whether one object is 'compatible' with another object.

For example, if we have a Person class. We also have a have an Employee class and a Manager class that inherits from the Person class (don't get too 'hung up' on the specifics of the Person class. Just think of it as a way to relate Manager and Employee classes that will allow us to treat Manager and Employee objects as Person objects):

Person class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AsIsKeywords
{
    abstract class Person
    {
        public abstract string name { get; set; }      //all people should have a name, hence why this is in the base class.
                                                       //Manager and Employee will inherit from this, thus allowing us to treat
                                                       //them as 'people' (i.e. of type Person). This class relates the Manager and
                                                       //Employee classes 
                                                 
    }
}




Manager Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AsIsKeywords
{
    class Manager:Person
    {
        public override string name { get; set; }      //override base class name property

        public Manager(string name)
        {
            this.name = name; //set name
        }

        public void OrderEmployeesAbout()     //this is a method we will be calling
        {
            Console.WriteLine("Do some work!");
        }
    }
}




Employee class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AsIsKeywords
{
    class Employee:Person
    {
        public override string name { get; set; }        //override base class property

        public Employee(string name)
        {
            this.name = name; //set name
        }

        public void DoWork()                   //again, this is what we are interested in and is what we will be calling. It makes the employee do work.
        {
            Console.WriteLine("I'm doing some work!");
        }
    }
}




Now, say we have an array of type Person. This array can hold any Person objects. However, crucially, it can hold ANY objects that derive from Person. Think about it this way, an Employee IS-A Person. It therefore makes complete sense that the array should also be able to hold Employee objects, and Manager objects, seeing as they are people. Therefore, we fill this array with Manager and Employee objects. This array will be in or main 'Program' class:

private static Person[] personArray = new Person[] { new Manager("John"), new Manager("Charlie"), new Employee("Stuart") };


As you can see, this Person array holds 2 managers and one employee.

Say we now want to loop through the array, and call OrderEmployeesAbout() if the current element is a Manager, and call DoWork() if the current element is an Employee object. We now have a problem.

Remember, we are getting Person object back from the array, and Person objects have no such methods (the Person class only defines one abstract property). Due to the fact that a Manger IS-A Person (i.e. it is derived from Person), we will be able to cast the Person objects to the correct underlying type (Manager or Employee), and therefore get access to the method we require from each type. Great!

However, how do we know which Person objects are Managers and which ones are Employees. Think about it this way, if we were given a random person we had never met before, we wouldn't be able to tell whether he was a manager or an employee (or indeed whether he was neither!). However, given a manager or an employee, we know they are a person, no matter what. (obviously). This is similar logic to why we need to cast the Person objects to Manager or Employee types to gain access to the Employee and Manager specific methods, but do not need a cast to place the Manager and Employee objects into the above 'person' array (as they are definately, themselves, people, no matter what! As they inherit from the Person class)

However, without knowing whether the current Person object from the array is a Manager or Employee, how do we know what to cast the Person object too?

This is where the ‘is’ keyword comes in. Using this keyword, we can check whether or not the current Person object IS-A Manager or whether it IS-A Employee. See the example below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AsIsKeywords
{
    class Program
    {
        private static Person[] personArray = new Person[] { new Manager("John"), new Manager("Charlie"), new Employee("Stuart") };

        static void Main(string[] args)
        {
            Manager manager;              //temp variables to hold Manager and Employee objects after we have cast
                                         //the Person objects to the Manager or Employee type. We then use these variables
                                         //to call the DoWork or OrderEmployeesAbout methods
            Employee employee;

           foreach (Person p in personArray)
            {
                if (p is Manager){                          //check if current Person object is a Manager, returns true if it is, false if not
                    manager = (Manager)p;                   //if current Person object is a Manager, we cast it to the manager type and call 
                                                            //the relevant OrderEmployeesAbout method
                    manager.OrderEmployeesAbout();
                }
                else if (p is Employee){                    //check if current Person object is an Employee, returns true if it is, false if not          
                    employee = (Employee)p;                 //if it is an Employee, we cast the Person object to an Employee object
                                                           //and then call the relevant DoWork method
                    employee.DoWork();
                }

            }
        }
    }
}



All we are doing here is looping through the array, and checking if the current element is a Manager or an Employee. If it is an Employee, we cast it ourselves to the Employee type and store the referene to it in the 'employee' variable, and then call DoWork(). If it’s a Manager, we cast it ourselves to a Manager type, store the reference to it in the 'manager' variable, and then call OrderEmployeesAbout().

Think of it like this. We are checking whether ‘p’ (i.e. the current Person object) is a Manager or an Employee, and performing actions depending on the results of these checks.

This is one way of checking whether we are dealing with a Manager or an Employee. However, there is another, similar way to do this. Although, with this way, we check and cast the Person objects to the correct type in one expression, as it were. This ‘way’ is the ‘as’ keyword. We shall cover the ‘as’ keyword next.


The 'as' Keyword

This is the exact same Program as was used with the 'is' keyword example. However, this time the code inside the foreach loop is slightly different:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AsIsKeywords
{
    class Program
    {
        private static Person[] personArray = new Person[] { new Manager("John"), new Manager("Charlie"), new Employee("Stuart") };

        static void Main(string[] args)
        {
            Manager manager;
            Employee employee;

           foreach (Person p in personArray)
            {
               //in the if condition, we firstly try and cast the current person, 'p' AS a Manager.
               //if the cast succeeds, manager is set to the new Manager object. If the cast fails
               //i.e. the current Person object is NOT a Manager, it returns null. Therefore, if the 'manager'
               //variable is not equal to 'null', we know the cast succeeded and we are safe to call the
               //OrderEmployeesAbout method. The same principle is used for Employee objects.


                if ((manager = p as Manager) != null) manager.OrderEmployeesAbout();
                else if ((employee = p as Employee) != null) employee.DoWork();


               //NOTICE HOW THE 'as' KEYWORD PERFORMS THE 'CHECK' FOR US, BUT ALSO PERFORMS THE CAST FOR
               //US WHERE IT CAN. THE 'is' KEYWORD DOES NOT PERFORM ANY CASTING, IT JUST PERFORMS THE CHECK
               //AND LEAVES US TO DO THE CASTING OURSELVES.
            }
        }
    }
}




The difference this time is that, before we were checking if the current element could be cast to a Manager, for example, then we were performing the cast manually ourselves if the conditional evaluated to true. However, with the ‘as’ keyword, this is taken care of for us. The ‘as’ keyword checks to see if the item can be cast as a Manger, if it can, it performs the cast (so we don't have too...). If it cannot, it returns null. Therefore, we avoid the extra work of having to cast the Person objects manually. The ‘as’ keyword takes the ‘is’ keyword one step further, in order to make life easier. It checks, and performs the cast if possible, all in one! As opposed to just checking if the cast is possible, like the 'is' keyword does.

The Output

The output for using the 'is' method and the 'as' method is EXACTLY the same. We get to lines that say "Do some work!" (corresponding to the two Manager objects that were the first two elements in the array and therefore the first ones accessed). The final line corresponds to the Employee object, and consequently prints "I'm doing some work!".


Quote

Do some Work!
Do some Work!
I'm doing some work!



Summary

‘is’

This keyword is a checking mechanism only. It merely checks whether or not the left hand operand can be cast to the right hand operand. In our example, it checks whether the current Person object IS-A Manager or not (it performs another check for Employees too). It returns true if it is (and can therefore be cast to such a type), and false if it isn’t (and so cannot be cast). There is no casting at all going on…only a check to see whether a cast is possible.

‘as’

The ‘as’ keyword performs the same check that the ‘is’ keyword does. Except if the Person object IS-A manager and can therefore be cast to the Manager type, it performs the cast for you there and then. That is the difference. The ‘as’ keyword takes the functionality of the ‘is’ keyword one step further in that it actually performs the cast for you. Also, of course, where the object cannot be cast to the relevant type, the ‘as’ keyword returns ‘null’, whereas the ‘is’ keyword returns false.

The fact that the ‘as’ keyword returns null can be used to your advantage. If you do not want failed casts to throw exceptions, you use the ‘as’ keyword to attempt the cast, as if it fails, null is returned. This is in contrast to using the bracket casting method like this:

employee = (Employee)p //casting the person object to an Employee object.


If that cast fails, an exception is thrown. If this cast fails:

employee = p as Employee //same cast as before


then all that will happen is that the ‘employee’ will be set to null. No exception will be thrown.


In our example though, the 'as' operator is the more compact solution. Although the use of the 'is' operator does works as intended too. It's, to a degree, a matter of preference which one you use and, also, it somewhat depends on what context you are working in and what you want to achieve. Now you know the differences, I am confident that you could make the decision quite easily :).


Extra Resources on the ‘is’ and ‘as’ Keywords


http://msdn.microsof...9xw(VS.71).aspx

http://msdn.microsof...fbt(VS.71).aspx



Thank you very much. I hope this little tutorial helped someone :). It's just one of them basic things that everyne should get to grips with.

If you didn't quite get the use of the abstract Person class, don't worry. That wasn't the point of the tutorial. Just think of the Person class as something that allows us to treat both Managers and Employees as Person objects, and hence put them in an array of type Person.

P.S. I have attached the files used in this tutorial. I have added a few more comments in the attached code files. They are very basic, but demonstrate the point I think :). Try adding new Manager and Employee objects to the array and see if it still works...

Any suggestions, comments or questions, just leave a quick comment below.

Thank you.

Attached File(s)



Is This A Good Question/Topic? 6
  • +

Replies To: The 'is' and 'as' Keywords

#2 5thWall  Icon User is offline

  • Occasional Member

Reputation: 31
  • View blog
  • Posts: 530
  • Joined: 17-September 08

Posted 26 October 2010 - 08:19 AM

And all this time I thought as was just syntactic sugar for a normal cast. I might be able to shorten up some code with this.
Was This Post Helpful? 0
  • +
  • -

#3 Gergan  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 10
  • Joined: 15-April 14

Posted 06 June 2014 - 05:03 PM

Nice tutorial man :))

But I got one question..

In the end it's almost the same.. 'is' operator is doing casting if object can be cast to another object..
'as' is doing the same .. just difference is in returning, 'is' is returning boolean, 'as' is returning null..??

And if we'r workin with value types (All numeric data types, boolean , char, and date) we must use explicit casts, otherwise we'll receive error, because 'is' and 'as' can not be used on value types (casting value to value, example int to double)..

I did one exercise using both operators.. so I can't figure out what's really diference between them (except their returns)..??

USING AS

static void Main()
    {
        object[] objArray = new object[6];
        objArray[0] = new ClassA();
        objArray[1] = new ClassB();
        objArray[2] = "hello";
        objArray[3] = 123;
        objArray[4] = 123.4;
        objArray[5] = null;

        for (int i = 0; i < objArray.Length; ++i)
        {
            string s = objArray[i] as string;
            Console.Write("{0}:", i);
            if (s != null)
            {
                Console.WriteLine("'" + s + "'");
            }
            else
            {
                Console.WriteLine("not a string");
            }
        }
    }



USING IS

 class Program
        {
            static void Main()
            {

                    object[] objArray = new object[6];
                    objArray[0] = 1;
                    objArray[1] = 2;
                    objArray[2] = "hello";
                    objArray[3] = "Hey!";
                    objArray[4] = 123.4;
                    objArray[5] = null;

                    for (int i = 0; i < objArray.Length; ++i)
                    {
                      

                     

                        if (objArray[i] is string)
                        {
                            Console.WriteLine("'" + objArray[i] + "'");
                        }

                        else
                        {
                            Console.WriteLine("not a string");
                        }
                    }
                }
                    


Was This Post Helpful? 0
  • +
  • -

#4 charles1990  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 20-June 14

Posted 25 June 2014 - 04:24 AM

Nice tutorial am now cleared. Thanks man

Nice tutorial am now cleared. Thanks man
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1