Tải bản đầy đủ (.pdf) (6 trang)

Understanding Conversion Operators

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (24.22 KB, 6 trang )



Understanding Conversion Operators
Sometimes it is necessary to convert an expression of one type into another. For example,
the following method is declared with a single double parameter:
class Example
{
public static void MyDoubleMethod(double parameter)
{
...
}
}
You might reasonably expect that only values of type double could be used as arguments
when calling MyDoubleMethod, but this is not so. The C# compiler also allows
MyDoubleMethod to be called with an argument whose type is not double, but only as
long as that value can be converted to a double. The compiler will generate code that
performs this conversion when the method is called.
Providing Built-In Conversions
The built-in types have some built-in conversions. For example, an int can be implicitly
converted to a double. An implicit conversion requires no special syntax and never
throws an exception:
Example.MyDoubleMethod(42); // implicit int to double conversion
An implicit conversion is sometimes called a widening conversion, as the result is wider
than the original value—it contains at least as much information as the original value, and
nothing is lost.
On the other hand, a double cannot be implicitly converted to an int:
class Example
{
public static void MyIntMethod(int parameter)
{
...


}
}
...
Example.MyIntMethod(42.0); // compile-time error
Converting from a double to an int runs the risk of losing information, so it will not be
done automatically (consider what would happen if the argument to MyIntMethod was
42.5—how should this be converted?) A double can be converted to an int, but the
conversion requires an explicit notation (a cast):
Example.MyIntMethod((int)42.0);
An explicit conversion is sometimes called a narrowing conversion as the result is
narrower than the original value (it can contain less information), and can throw an
OverflowException. C# allows you to provide conversion operators for your own user-
defined types to control whether they can be implicitly or explicitly converted to other
types.
Implementing User-Defined Conversion Operators
The syntax for declaring a user-defined conversion operator is similar to an overloaded
operator. A conversion operator must be public and must also be static. Here's a
conversion operator that allows an Hour object to be implicitly converted into an int:
struct Hour
{
...
public static implicit operator int (Hour from)
{
return this.value;
}

private int value;
}
The type you are converting from is declared as the single parameter (in this case, Hour),
and the type you are converting to is declared as the type name after the keyword

operator (in this case, int). There is no return type specified before the keyword operator.
When declaring your own conversion operators, you must specify whether they are
implicit conversion operators or explicit conversion operators. You do this by using the
implicit and explicit keywords. For example, the Hour to int conversion operator
mentioned previously is implicit, meaning that the C# compiler can use it implicitly
(without a cast):
class Example
{
public static void Method(int parameter) { ... }
public static void Main()
{
Hour lunch = new Hour(12);
Example.MyOtherMethod(lunch); // implicit Hour to int conversion
}
}
If the conversion operator had been declared explicit, the previous example would not
have compiled because an explicit conversion operator requires an explicit cast:
Example.MyOtherMethod((int)lunch); // explicit Hour to int conversion
When should you declare a conversion operator as explicit or implicit? If a conversion is
always safe, does not run the risk of losing information, and cannot throw an exception,
then it can be defined as an implicit conversion. Otherwise, it should be declared as an
explicit conversion. Converting from an Hour to an int is always safe—every Hour has a
corresponding int value—so it makes sense for it to be implicit. An operator that
converted a string to an Hour should be explicit, as not all strings represent valid Hours.
(While the string “7” is fine, how would you convert the string “Hello, World” into an
Hour?)
Creating Symmetric Operators Revisited
Conversion operators provide you with an alternate way to resolve the problem of
providing symmetric operators. For example, instead of providing three versions of
operator+ (Hour + Hour, Hour + int, and int + Hour) for the Hour struct as shown earlier,

you can provide a single version of operator+ (that takes two Hour parameters) and an
implicit int to Hour conversion, like this:
struct Hour
{
public Hour(int initialValue)
{
this.value = initialValue;
}

public static Hour operator+(Hour lhs, Hour rhs)
{
return new Hour(lhs.value + rhs.value);
}

public static implicit operator Hour (int from)
{
return new Hour (from);
}
...
private int value;
}
If you add an Hour and an int (in either order), the C# compiler automatically converts
the int to an Hour and then calls operator+ with two Hour arguments:
void Example(Hour a, int b)
{
Hour eg1 = a + b; // b converted to an Hour Hour eg2 = b + a; //
b converted to an Hour
}
Adding an Implicit Conversion Operator
In the following exercise, you will modify the digital clock application from the previous

exercise. You will add an implicit conversion operator to the Second struct and remove
the operators that it replaces.
Write the conversion operator
1. Return to Visual Studio 2005 displaying the Operators project. Display the
Clock.cs file in the Code and Text Editor window and examine the tock method
again:
2. private void tock()
3. {
4. this.second++;
5. if (this.second == 0)
6. {
7. this.minute++;
8. if (this.minute == 0)
9. {
10. this.hour++;
11. }
12. }
}
Notice the statement if (this.second == 0). This fragment of code compares a
Second to an int using the == operator.
13. In the Code pane, open the Second.cs source file.
The Second struct currently contains three overloaded implementations of
operator== and three overloaded implementations of operator!=. Each operator is
overloaded for the parameter type pairs (Second, Second), (Second, int), and (int,
Second).
14. In the Code and Text Editor window, delete the versions of operator== and
operator!= that take one Second and one int parameter (do not delete the operators
that take two Second parameters). The following three operators should be the
only operators in the Second struct (there will be other methods, however):
15. struct Second

16. {
17. ...
18. public static bool operator==(Second lhs, Second rhs)
19. {
20. return lhs.value == rhs.value;
21. }
22.
23. public static bool operator!=(Second lhs, Second rhs)
24. {
25. return lhs.value != rhs.value;
26. }
27. ...
}
28. On the Build menu, click Build Solution.
The build fails with the message:
Operator '==' cannot be applied to the operands of type 'Operators.Second' and 'int'
Removing the operators that compare a Second and an int cause the statement
highlighted earlier to fail to compile.
29. In the Code and Text Editor window, add an implicit conversion operator to the
Second struct that converts from an int to a Second.
The conversion operator should look like this:
struct Second
{
...
public static implicit operator Second (int arg)
{

×