Conversions


Throughout the book so far, you have used casting whenever you have needed to convert one type into another. However, this isn't the only way to do things. In the same way that an int can be converted into a long or a double implicitly as part of a calculation, it is possible to define how classes you have created may be converted into other classes (either implicitly or explicitly). To do this, you can overload conversion operators, in much the same way as other operators were overloaded earlier in this chapter. You'll look at this in the first part of this section.

Also in this section, you'll see another useful operator, the as operator, which in general is preferable to casting when using reference types.

Overloading Conversion Operators

As well as overloading mathematical operators, as shown earlier, you can define both implicit and explicit conversions between types. This is necessary if you want to convert between types that aren't related, if there is no inheritance relationship between them and no shared interfaces, for example.

Say that you define an implicit conversion between ConvClass1 and ConvClass2. This means that you can write code such as:

 ConvClass1 op1 = new ConvClass1(); ConvClass2 op2 = op1; 

Alternatively, you can define an explicit conversion, called in the following code:

 ConvClass1 op1 = new ConvClass1(); ConvClass2 op2 = (ConvClass2)op1; 

As an example, consider the following code:

 public class ConvClass1 { public int val; public static implicit operator ConvClass2(ConvClass1 op1) { ConvClass2 returnVal = new ConvClass2(); returnVal.val = op1.val; return returnVal; } } public class ConvClass2 { public double val; public static explicit operator ConvClass1(ConvClass2 op1) { ConvClass1 returnVal = new ConvClass1(); checked {returnVal.val = (int)op1.val;}; return returnVal; } } 

Here, ConvClass1 contains an int value and ConvClass2 contains a double value. Since int values may be converted into double values implicitly, you can define an implicit conversion between ConvClass1 and ConvClass2. The reverse is not true, however, and you should define the conversion operator between ConvClass2 and ConvClass1 as explicit.

In the code, you specify this using the implicit and explicit keywords as shown.

With these classes the following code is fine:

 ConvClass1 op1 = new ConvClass1(); op1.val = 3; ConvClass2 op2 = op1; 

A conversion in the other direction, however, requires the following explicit casting conversion:

 ConvClass2 op1 = new ConvClass2(); op1.val = 3e15; ConvClass1 op2 = (ConvClass1)op1; 

Note that as you have used the checked keyword in your explicit conversion, you will get an exception in the preceding code, since the val property of op1 is too large to fit into the val property of op2.

The as Operator

The as operator converts a type into a specified reference type, using the following syntax:

 <operand> as <type> 

This is only possible in certain circumstances:

  • If <operand> is of type <type>

  • If <operand> can be implicitly converted to type <type>

  • If <operand> can be boxed into type <type>

If no conversion from <operand> to <type> is possible, then the result of the expression will be null.

Note that conversion from a base class to a derived class is possible using an explicit conversion, but it won't always work. Consider the two classes ClassA and ClassD from an earlier example, where ClassD inherits from ClassA:

class ClassA : IMyInterface { }     class ClassD : ClassA { }

The following code uses the as operator to convert from a ClassA instance stored in obj1 into the ClassD type:

 ClassA obj1 = new ClassA(); ClassD obj2 = obj1 as ClassD; 

This will result in obj2 being null.

However, it is possible to store ClassD instances in ClassA-type variables using polymorphism. The following code illustrates this, and uses the as operator to convert from a ClassA-type variable containing a ClassD-type instance into the ClassD type:

 ClassD obj1 = new ClassD(); ClassA obj2 = obj1; ClassD obj3 = obj2 as ClassD; 

This time the result is that obj3 ends up containing a reference to the same object as obj1, not null.

This functionality makes the as operator very useful, because the following code using simple casting results in an exception being thrown:

 ClassA obj1 = new ClassA(); ClassD obj2 = (ClassD)obj1; 

The as equivalent of this code results in a null value being assigned to obj2 — no exception is thrown. This means that code such as the following (using two of the classes developed earlier in this chapter, Animal and a class derived from Animal called Cow) is very common in C# applications:

 public void MilkCow(Animal myAnimal) { Cow myCow = myAnimal as Cow; if (myCow != null) { myCow.Milk(); } else { Console.WriteLine("{0} isn't myAnimal.Name); } } 

This is much simpler than checking for exceptions!




Beginning Visual C# 2005
Beginning Visual C#supAND#174;/sup 2005
ISBN: B000N7ETVG
EAN: N/A
Year: 2005
Pages: 278

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