Inheritance With AS, IS and Cast Operators

IS Keyword

IS does not compare objects, it checks the object for its type.

For example:

                        "abc" string gives TRUE,
                        "abc" is int gives False,
                         "abc" is "abc" gives compile time error because it cannot be used to compare two types.

So, a comparison is not done by IS, only checking is done.

  1. namespace IsAndAsOperators {  
  2.     class Person {  
  3.         public int Id {  
  4.             get;  
  5.             set;  
  6.         }  
  7.         public string Name {  
  8.             get;  
  9.             set;  
  10.         }  
  11.         public int Age {  
  12.             get;  
  13.             set;  
  14.         }  
  15.     }  
  16.     class Alien {  
  17.         public int ID {  
  18.             get;  
  19.             set;  
  20.         }  
  21.         public string Name {  
  22.             get;  
  23.             set;  
  24.         }  
  25.         public int Age {  
  26.             get;  
  27.             set;  
  28.         }  
  29.     }  
  30.     class Program {  
  31.         static void Main(string[] args) {  
  32.             Person pobj = new Person();  
  33.             pobj.Id = 1;  
  34.             pobj.Name = "GOGO";  
  35.             pobj.Age = 15;  
  36.             Alien aobj = new Alien();  
  37.             aobj.ID = 20;  
  38.             aobj.Name = "POGO";  
  39.             aobj.Age = 25;  
  40.             // Is operator  
  41.             bool issame = (aobj is Person);  
  42.             System.Console.WriteLine("Alien is a Person ?: {0}", issame.ToString()); //FALSE  
  43.             issame = (pobj is Person);  
  44.             System.Console.WriteLine("Person is a Person ?: {0}", issame.ToString()); //TRUE  
  45.             System.Console.ReadLine();  
  46.         }  
  47.     }  
  48. }  
Inheritance Case in IS operator

Now what happens if Alien inherit from Person (alien that evolved as earth Person over time) .

  1. namespace IsAndAsOperators {  
  2.     class Person {  
  3.         public int Id {  
  4.             get;  
  5.             set;  
  6.         }  
  7.         public string Name {  
  8.             get;  
  9.             set;  
  10.         }  
  11.         public int Age {  
  12.             get;  
  13.             set;  
  14.         }  
  15.     }  
  16.     class Alien: Person {  
  17.         public int ID {  
  18.             get;  
  19.             set;  
  20.         }  
  21.         public string NAME {  
  22.             get;  
  23.             set;  
  24.         }  
  25.         public int AGE {  
  26.             get;  
  27.             set;  
  28.         }  
  29.     }  
  30.     class Program {  
  31.         static void Main(string[] args) {  
  32.             Person pobj = new Person();  
  33.             pobj.Id = 1;  
  34.             pobj.Name = "GOGO";  
  35.             pobj.Age = 15;  
  36.             Alien aobj = new Alien();  
  37.             aobj.ID = 20;  
  38.             aobj.Name = "POGO";  
  39.             aobj.Age = 25;  
  40.             // Is operator  
  41.             bool issame = (aobj is Person);  
  42.             System.Console.WriteLine("Alien is a Person ?: {0}", issame.ToString()); //TRUE  
  43.             issame = (pobj is Person);  
  44.             System.Console.WriteLine("Person is a Person ?: {0}", issame.ToString()); //TRUE  
  45.             System.Console.ReadLine();  
  46.         }  
  47.     }  
  48. }  

AS operator

The AS operator gives a reference of various types. Say object r1 = "abc", then string r2 = r1 as string means r2 is the same as r1 but as a string, whereas Uri r3 = r1 as Uri means r3 is null because r1 wasn't a Uri so this couldn't work.

So the AS operator gives a reference if it can be done, else it gives NULL.

CODE

  1. namespace IsAndAsOperators {  
  2.     class Person {  
  3.         public int Id {  
  4.             get;  
  5.             set;  
  6.         }  
  7.         public string Name {  
  8.             get;  
  9.             set;  
  10.         }  
  11.         public int Age {  
  12.             get;  
  13.             set;  
  14.         }  
  15.     }  
  16.     class Alien {  
  17.         public int ID {  
  18.             get;  
  19.             set;  
  20.         }  
  21.         public string Name {  
  22.             get;  
  23.             set;  
  24.         }  
  25.         public int Age {  
  26.             get;  
  27.             set;  
  28.         }  
  29.     }  
  30.     class Program {  
  31.         static void Main(string[] args) {  
  32.             Person pobj = new Person();  
  33.             pobj.Id = 1;  
  34.             pobj.Name = "GOGO";  
  35.             pobj.Age = 15;  
  36.             Alien aobj = new Alien();  
  37.             aobj.ID = 20;  
  38.             aobj.Name = "POGO";  
  39.             aobj.Age = 25;  
  40.             // AS operator  
  41.             System.Console.WriteLine("Alien is a Person ?: {0}", useAS(aobj)); //False  
  42.             System.Console.WriteLine("Person is a Person ?: {0}", useAS(pobj)); //TRUE  
  43.             System.Console.ReadLine();  
  44.         }  
  45.         private static string useAS(dynamic aobj) {  
  46.             // If obj is Type Person it asign value to obj else it asign null  
  47.             Person obj = aobj as Person;  
  48.             if (obj != nullreturn "This is a Person and his name is " + obj.Name;  
  49.             return "Not a Person";  
  50.         }  
  51.     }  
  52. }  

AS with Inheritance

Now what happens if Alien inherits from Person (alien that evolved as earth Person over time).

  1. namespace IsAndAsOperators   
  2. {  
  3.     class Person {  
  4.         public int Id   
  5.         {  
  6.             get;  
  7.             set;  
  8.         }  
  9.         public string Name   
  10.         {  
  11.             get;  
  12.             set;  
  13.         }  
  14.         public int Age   
  15.         {  
  16.             get;  
  17.             set;  
  18.         }  
  19.     }  
  20.     class Alien: Person {}  
  21.     class Program {  
  22.         static void Main(string[] args)   
  23.         {  
  24.             Person pobj = new Person();  
  25.             pobj.Id = 1;  
  26.             pobj.Name = "GOGO";  
  27.             pobj.Age = 15;  
  28.             Alien aobj = new Alien();  
  29.             aobj.Id = 20;  
  30.             aobj.Name = "POGO";  
  31.             aobj.Age = 25;  
  32.             // AS operator  
  33.             System.Console.WriteLine("Alien is a Person ?: {0}", useAS(aobj)); //TRUE  
  34.             System.Console.WriteLine("Person is a Person ?: {0}", useAS(pobj)); //TRUE  
  35.             System.Console.ReadLine();  
  36.         }  
  37.         private static string useAS(dynamic aobj)   
  38.         {  
  39.             // If obj is Type Person it asign value to obj else it asign null  
  40.             Person obj = aobj as Person;  
  41.             if (obj != nullreturn "This is a Person and his name is :" + obj.Name;  
  42.             return "Not a Person";  
  43.         }  
  44.     }  
  45. }  

CAST Operator

Let's explain this by the code first approach. We will see various ways to cast objects.

Let us say we have:

  1. void TestProgram(object o, EventArgs e)   
  2. {  
  3.     //o is a string  
  4.     string s = (string) o; // 1 (Casting)  
  5.     //-OR-  
  6.     string s = o as string// 2 (Use of AS)  
  7.     // -OR-  
  8.     string s = o.ToString(); // 3 (.tostring method)  
  9. }  

What is the difference between all these?

Using thoughts of Sander (since he explained this in the best possible way):

  1. Throws InvalidCastException if o is not a string, otherwise assigns o to s, even if o is null. (Use this for most conversions.)

  2. Assigns null to s if o is not a string or if o is null. For this reason, you cannot use it with value types (the operator could never return null in that case), otherwise assigns o to s. (Try to never use 2 since if something is not of the right type, I usually expect an exception to occur. I have only seen a need for this return-null type of functionality with badly designed libraries which use error codes, for example, return null = error instead of using exceptions).

  3. Causes a NullReferenceException if o is null. Assigns whatever o.ToString() returns to s, no matter what type o is. (Use it for when you need the string representation of a non-string object.)

BASIC- (int) value and "value as int" is that the former throws an exception if the conversion fails, whereas the latter returns null.

More details about CAST

We can cast only if we know what type it will be. What it means is explained by Boxing and Unboxing.

Here's the code:

  1. static string[] args)  
  2.   
  3. {  
  4.     short a = 10;  
  5.   
  6.     object o = (object) a;  
  7.   
  8.     int b = (int) o; //Illegal  
  9.   
  10.     Console.WriteLine(b.ToString());  
  11.   
  12.     Console.ReadLine();  
  13. }  

Here it is not possible since the compiler does not know how to unbox it. A short can be unboxed as a short only.

However:

  1. int jjj = (int) (short) ooo; // Perfectly legal  
Reason

When a value is boxed as an Object then when unboxing the compiler does not know to which type it needs to be unboxed to. So if it's a short it needs to generate code to convert it into a short. If it's an int then it needs to generate code for an int and then there are many other complex types. Basically there will be a huge amount of code to generate and it would be very slow.
 
The code is of course so large that you would want to put it in its own method and just generate a call to it. Rather than do that by default and always generate code that is slow, large and fragile, instead we've decided that unboxing can only unbox to the exact type. If you want to call the slow method that does everything then it's available, you can always call Convert.ToInt32 that does all the analysis at runtime for you. We give you the choice between “fast and precise” or “slow and lax”, and the sensible default is the former. If you want the latter then call the method. So to make life a bit easy, C# 4.0 added the new keyword "Dynamic" instead of "object". We will explain it in the next article.