Converting From One Type to Another (Casting)


See, it's just a compiler thing . . . The C# compiler is type safe. You may have heard that phrase before when referring to other compilers, like the C++ or the Java compiler. To be type safe means that when you make a method call through a variable, the compiler only allows you to call methods that belong to the class of the type of the variable. If the variable is of type Mouse, then you can only call Mouse methods even if the object the variable points to is of type SuperheroMouse or EntrepreneurMouse . In Figure 7.12 you see that even though the variable mickey points to an object of type EntrepreneurMouse , and EntrepreneurMouse has a method called ChargeOutrageousPrices , because the variable mickey is of type Mouse you can't call the method ChargeOutrageousPrices , you can only call methods that are part of the class Mouse . That's because, like I said at the beginning, it's a compiler thing. The compiler looks at the type of the variable and ensures that you only call methods that are part of the class of the type of the variable. If you wanted to call ChargeOutrageousPrices through mickey , you would have to cast mickey into EntrepreneurMouse first ( Figure 7.13 ). Casting means you can turn one object into a different type as long as the object is compatible with that type. You learned how to test if an object is compatible with another in the previous section, "Testing for Type Compatibility." There are two ways to cast one type into another: one is using the explicit cast operator and one is using the as operator in C#.

Figure 7.12 Even though mickey is of type EntrepreneurMouse , because the variable is of type Mouse, the only method the compiler lets you invoke is EatCheese.
 class Mouse {    public void EatCheese()    {    } } class SuperheroMouse : Mouse {    public void DefeatEvildoers()    {    } } class EntrepreneurMouse : Mouse {    public void ChargeOutrageousPrices()    {    } } Mouse mickey = new EntrepreneurMouse(); //mickey.  ChargeOutrageousPrices(); //***illegal  mickey  .EatCheese()  ; 
Figure 7.13 When you cast (by putting a type name in parentheses in front of the variable) you're telling the compiler to treat the variable as the type in parenthesis. This makes it possible to call methods that are part of the class to which you are casting.
 //see Figure 7.7 for details on the classes Mouse mickey = new EntrepreneurMouse(); (  (EntrepeneurMouse)  mickey).ChargeOutrageous Prices(); mickey.EatCheese(); 

To cast one type into another using explicit casts:

  1. Declare a variable of the type you wish to convert to. For example: SuperheroMouse mightyMouse .

  2. Type an equal sign = .

  3. Type the name of the type you wish to convert to in parentheses. For example: (SuperheroMouse) .

  4. Type the name of the variable that contains the object you wish to convert ( Figure 7.14 ).

    Figure 7.14 You may be familiar with this type of cast if you have done some C++ programming.
     //see Figure 7.7 for details on the classes Mouse anyMouse = new SuperheroMouse(); SuperheroMouse mightyMouse =  (SuperheroMouse)  anyMouse; 

To cast using the as operator:

  1. Declare a variable of the type you wish to convert to. For example: Superhero mightyMouse .

  2. Type an equal sign = .

  3. Type var as Superhero , where var is the name of the variable that contains the object you wish to convert and Superhero is the type you are converting to ( Figure 7.15 ).

    Figure 7.15 This type of cast is new to C#. It's safer than doing the explicit cast in Figure 7.14 because if the cast fails you don't get an exception, rather the result of the cast would be null.
     //see Figure 7.7 for details on the classes Mouse anyMouse = new SuperheroMouse(); SuperheroMouse mightyMouse = anyMouse  as SuperheroMouse  ; 

graphics/tick.gif Tips

  • If the object you are converting isn't compatible with the type you are converting tofor example you are casting an object of type TwoYearOld into a QuietPerson typeand you use an explicit cast, the system will generate an exception (an error) at runtime. Figure 7.16 shows you how to capture the error and Figure 7.17 shows the exception you would get if you didn't capture the error.

    Figure 7.16 If you pay close attention to the sample code, you may notice that in the second line I use an object variable and then try to cast the object variable to QuietPerson . The reason I do that is because if I tried to cast from TwoYeardOld directly to QuietPerson the compiler would stop me telling me that the conversion would fail.
     TwoYearOld Tommy = new TwoYearOld(); object obj = Tommy; try {    QuietPerson quiet = (QuietPerson)obj; } catch(InvalidCastException) {    Resonse.Write("Object is not a Quiet Person"); } 
    Figure 7.17. This is the error you would see if you fail to capture the error. The exception type is InvalidCastException . Figure 7.16 shows you how to capture the error with a try/catch block. You'll learn about try/catch blocks in Chapter 11.

    graphics/07fig17.gif

  • It's best to first test if the type is compatible before attempting an explicit cast even if you're careful to trap the error because capturing exceptions is considered a performance costly operation (and the Microsoft police will beat you senseless).

  • The advantage of using the second mechanism is that if the type isn't compatible with the type to which you are casting, the runtime returns a null. Figure 7.18 shows you how to test for null to see if the cast succeeded.

    Figure 7.18 The good thing about this technique is that the conversion only happens if the types are compatible; if they aren't compatible, the .NET Framework just returns a null.
     TwoYearOld Tommy = new TwoYearOld(); object obj = Tommy; QuietPerson quiet =  obj as QuietPerson  ; if (  quiet == null  ) {    Response.Write(    "Sorry, object doesn't point to a quiet person."); } 
  • Some types can be converted to other types implicitlythe compiler knows how to convert between the types without you having to specify the type in parentheses. For example, a 32-bit integer (int) can be easily converted to a 64-bit integer (long) because there's no loss of information in the conversion. The rule of thumb is that you can do an implicit cast when the conversion doesn't result in loss of information. Thus, converting from a float to an integer would require an explicit cast, but converting from an integer to a float can be done implicitly ( Figure 7.19 ). Along the same lines, converting from a derived object to a base type can be done implicitly, because the derived type contains all the fields and methods of the base. But converting from a base class to a derived requires an explicit conversion ( Figure 7.20 ).

    Figure 7.19 With numeric types when there is no loss of data C# lets you do an implicit cast. However, when there is a potential loss of data, C# forces you to use an explicit cast.
     //it's fine to go from an int to //a float int age = 55;  float exactAge = age  ; //going back to an int from a float //requires an explicit conversion int normalAge =  (int)  exactAge; 
    Figure 7.20 The rule of thumb with classes is that you can always take a variable of a base type and assign it to an object of a derived type, but you can't go the other way without an explicit conversion.
     class Person { } class ExtendedFamily : Person { } class MotherInLaw : ExtendedFamily { } MotherInLaw law1 = new MotherInLaw(); ExtendedFamily ex1 = law1;  //implicit conversion   //going back to a derived   //type requires an explicit conversion  MotherInLaw law2 =  (MotherInLaw)  ex1; 



C#
C# & VB.NET Conversion Pocket Reference
ISBN: 0596003196
EAN: 2147483647
Year: 2003
Pages: 198
Authors: Jose Mojica

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net